@shapeshift-labs/frontier-lang-compiler 0.2.195 → 0.2.197

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 CHANGED
@@ -611,7 +611,7 @@ Recent residual closures represented in the matrix shards:
611
611
  - Module/export/import graph now records no-substitution template dynamic imports and parser-backed CommonJS helper `require` templates as static module edges while keeping expression templates proof-required.
612
612
  - Module/export/import graph now records no-substitution/static template host dependencies for `new URL`, workers, resolver calls, and `importScripts` while leaving expression templates unsupported.
613
613
  - Module/export/import graph now emits dynamic host dependency targets as `<host-dependency>` edges with expression hashes and proof-required unresolved evidence instead of omitting them.
614
- - CSS Modules graph records now infer local class export evidence from `.module.css` source via `@shapeshift-labs/frontier-lang-css`, while generated class-name maps, bundler transform identity, source-map proof, dynamic member access, writes, and helper-call equivalence remain fail-closed.
614
+ - CSS Modules graph records now infer local class export evidence, source-local composition graph hashes, export-only ICSS graph hashes, and project-source graph hashes for cross-file `composes` / ICSS imports when every referenced `.module.css` source is present and source-inferred; package/bundler-only composition, unresolved ICSS imports, generated class-name maps, bundler transform identity, source-map proof, dynamic member access, writes, and helper-call equivalence remain fail-closed without host evidence.
615
615
  - Type/public API graph now includes bounded TypeChecker assignability oracle proof for simple public type aliases while keeping semantic/runtime equivalence claims false.
616
616
  - JSX/TSX graph now records same-file and project-local named/default/barrel-import static component prop passthrough as `jsx-render-component-prop-flow-static-passthrough-evidence` and blocks dynamic callsite values with `jsx-render-component-prop-flow-dynamic-value-unsupported`.
617
617
  - JSX/TSX graph now records static `memo` / `forwardRef` / `observer` / `React.lazy` component wrapper chains as component-wrapper render-risk evidence while keeping render, lazy-load, and runtime equivalence explicitly unproved.
@@ -23,7 +23,9 @@ export interface NativeProjectSymbolGraphCssModuleImportBindingRecord {
23
23
  readonly generatedClassNameMapHash?: string;
24
24
  readonly jsTsUseSiteGraphHash?: string;
25
25
  readonly cssModuleCompositionGraphHash?: string;
26
+ readonly cssModuleCompositionGraphSource?: 'supplied' | 'source-local' | 'project-source' | string;
26
27
  readonly icssGraphHash?: string;
28
+ readonly icssGraphSource?: 'supplied' | 'source-export-only' | 'project-source' | string;
27
29
  readonly bundlerTransformHash?: string;
28
30
  readonly sourceMapProofHash?: string;
29
31
  readonly signatureHash?: string;
@@ -85,6 +87,10 @@ export interface NativeProjectSymbolGraphCssModuleUseSiteGraphRecord {
85
87
  readonly blockerCount: number;
86
88
  readonly generatedClassNameMapHash?: string;
87
89
  readonly cssModuleExportNamesHash?: string;
90
+ readonly cssModuleCompositionGraphHash?: string;
91
+ readonly cssModuleCompositionGraphSource?: 'supplied' | 'source-local' | 'project-source' | string;
92
+ readonly icssGraphHash?: string;
93
+ readonly icssGraphSource?: 'supplied' | 'source-export-only' | 'project-source' | string;
88
94
  readonly bundlerTransformHash?: string;
89
95
  readonly sourceMapProofHash?: string;
90
96
  readonly status: 'ready' | 'blocked' | string;
@@ -0,0 +1,255 @@
1
+ import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
+
3
+ function withProjectCssModuleDependencyGraphs(cssSourcesByPath) {
4
+ const enriched = new Map(cssSourcesByPath);
5
+ for (const [sourcePath, cssSource] of cssSourcesByPath.entries()) {
6
+ const cssModuleEvidence = cssSource?.cssModuleEvidence;
7
+ if (!cssModuleEvidence || cssSource.cssModuleEvidenceSource !== 'inferred-source') continue;
8
+ const computedCompositionGraphHash = cssModuleEvidence.cssModuleCompositionGraphHash
9
+ ? undefined
10
+ : projectCssModuleCompositionGraphHash(sourcePath, enriched);
11
+ const computedIcssGraphHash = cssModuleEvidence.icssGraphHash
12
+ ? undefined
13
+ : projectCssModuleIcssGraphHash(sourcePath, enriched);
14
+ if (!computedCompositionGraphHash && !computedIcssGraphHash) continue;
15
+ enriched.set(sourcePath, {
16
+ ...cssSource,
17
+ cssModuleEvidence: {
18
+ ...cssModuleEvidence,
19
+ cssModuleCompositionGraphHash: computedCompositionGraphHash ?? cssModuleEvidence.cssModuleCompositionGraphHash,
20
+ cssModuleCompositionGraphSource: computedCompositionGraphHash ? 'project-source' : cssModuleEvidence.cssModuleCompositionGraphSource,
21
+ icssGraphHash: computedIcssGraphHash ?? cssModuleEvidence.icssGraphHash,
22
+ icssGraphSource: computedIcssGraphHash ? 'project-source' : cssModuleEvidence.icssGraphSource,
23
+ proofGaps: cssModuleProofGapsWithout(cssModuleEvidence.proofGaps, [
24
+ ...(computedCompositionGraphHash ? ['css-module-composition-resolution-unproved'] : []),
25
+ ...(computedIcssGraphHash ? ['css-module-icss-graph-unproved'] : [])
26
+ ])
27
+ }
28
+ });
29
+ }
30
+ return enriched;
31
+ }
32
+
33
+ function projectCssModuleCompositionGraphHash(sourcePath, cssSourcesByPath) {
34
+ const source = projectCssModuleSource(sourcePath, cssSourcesByPath);
35
+ const compositions = cssModuleCompositions(source?.cssModuleEvidence);
36
+ if (!compositions.length) return undefined;
37
+ const graph = {
38
+ sources: new Map(),
39
+ edges: []
40
+ };
41
+ if (!visitCssModuleCompositionSource(sourcePath, cssSourcesByPath, graph, [])) return undefined;
42
+ return hashSemanticValue({
43
+ kind: 'frontier.lang.css.modules.projectCompositionGraph.v1',
44
+ rootSourcePath: sourcePath,
45
+ sources: sortedValues(graph.sources),
46
+ edges: graph.edges.sort(stableRecordCompare)
47
+ });
48
+ }
49
+
50
+ function visitCssModuleCompositionSource(sourcePath, cssSourcesByPath, graph, stack) {
51
+ if (graph.sources.has(sourcePath)) return true;
52
+ if (stack.includes(sourcePath)) return false;
53
+ const cssSource = projectCssModuleSource(sourcePath, cssSourcesByPath);
54
+ const evidence = cssSource?.cssModuleEvidence;
55
+ if (!evidence) return false;
56
+ const exportNames = cssModuleExportNames(evidence);
57
+ graph.sources.set(sourcePath, {
58
+ sourcePath,
59
+ sourceHash: evidence.sourceHash ?? cssSource.sourceHash,
60
+ moduleHash: evidence.moduleHash,
61
+ exportNames
62
+ });
63
+ for (const composition of cssModuleCompositions(evidence)) {
64
+ const sourceKind = composition.sourceKind ?? (composition.source ? 'file' : 'local');
65
+ if (sourceKind === 'file') {
66
+ const targetSourcePath = resolveRelativeCssSourcePath(sourcePath, composition.source);
67
+ const target = projectCssModuleSource(targetSourcePath, cssSourcesByPath);
68
+ if (!target) return false;
69
+ const targetExportNames = cssModuleExportNames(target.cssModuleEvidence);
70
+ if (composition.names?.some((name) => !targetExportNames.includes(name))) return false;
71
+ graph.edges.push(compositionGraphEdge(composition, {
72
+ sourcePath,
73
+ sourceKind,
74
+ targetSourcePath,
75
+ targetSourceHash: target.cssModuleEvidence?.sourceHash ?? target.sourceHash,
76
+ targetModuleHash: target.cssModuleEvidence?.moduleHash
77
+ }));
78
+ if (!visitCssModuleCompositionSource(targetSourcePath, cssSourcesByPath, graph, [...stack, sourcePath])) return false;
79
+ continue;
80
+ }
81
+ if (sourceKind !== 'local' && sourceKind !== 'global') return false;
82
+ graph.edges.push(compositionGraphEdge(composition, { sourcePath, sourceKind }));
83
+ }
84
+ return true;
85
+ }
86
+
87
+ function projectCssModuleIcssGraphHash(sourcePath, cssSourcesByPath) {
88
+ const source = projectCssModuleSource(sourcePath, cssSourcesByPath);
89
+ const evidence = source?.cssModuleEvidence;
90
+ if (!cssModuleIcssImports(evidence).length && !cssModuleIcssExports(evidence).length) return undefined;
91
+ const graph = {
92
+ sources: new Map(),
93
+ imports: [],
94
+ exports: []
95
+ };
96
+ if (!visitCssModuleIcssSource(sourcePath, cssSourcesByPath, graph, [])) return undefined;
97
+ return hashSemanticValue({
98
+ kind: 'frontier.lang.css.modules.projectIcssGraph.v1',
99
+ rootSourcePath: sourcePath,
100
+ sources: sortedValues(graph.sources),
101
+ imports: graph.imports.sort(stableRecordCompare),
102
+ exports: graph.exports.sort(stableRecordCompare)
103
+ });
104
+ }
105
+
106
+ function visitCssModuleIcssSource(sourcePath, cssSourcesByPath, graph, stack) {
107
+ if (graph.sources.has(sourcePath)) return true;
108
+ if (stack.includes(sourcePath)) return false;
109
+ const cssSource = projectCssModuleSource(sourcePath, cssSourcesByPath);
110
+ const evidence = cssSource?.cssModuleEvidence;
111
+ if (!evidence) return false;
112
+ graph.sources.set(sourcePath, {
113
+ sourcePath,
114
+ sourceHash: evidence.sourceHash ?? cssSource.sourceHash,
115
+ moduleHash: evidence.moduleHash,
116
+ icssExportNames: cssModuleIcssExportNames(evidence)
117
+ });
118
+ for (const exported of cssModuleIcssExports(evidence)) {
119
+ graph.exports.push({
120
+ sourcePath,
121
+ name: exported.name,
122
+ value: exported.value,
123
+ exportHash: exported.exportHash
124
+ });
125
+ }
126
+ for (const imported of cssModuleIcssImports(evidence)) {
127
+ const targetSourcePath = resolveRelativeCssSourcePath(sourcePath, imported.source);
128
+ const target = projectCssModuleSource(targetSourcePath, cssSourcesByPath);
129
+ if (!target) return false;
130
+ const targetExportNames = cssModuleIcssExportNames(target.cssModuleEvidence);
131
+ if (!targetExportNames.includes(imported.importedName)) return false;
132
+ graph.imports.push({
133
+ sourcePath,
134
+ targetSourcePath,
135
+ targetSourceHash: target.cssModuleEvidence?.sourceHash ?? target.sourceHash,
136
+ targetModuleHash: target.cssModuleEvidence?.moduleHash,
137
+ importedName: imported.importedName,
138
+ localName: imported.localName,
139
+ importHash: imported.importHash
140
+ });
141
+ if (!visitCssModuleIcssSource(targetSourcePath, cssSourcesByPath, graph, [...stack, sourcePath])) return false;
142
+ }
143
+ return true;
144
+ }
145
+
146
+ function projectCssModuleSource(sourcePath, cssSourcesByPath) {
147
+ if (!sourcePath) return undefined;
148
+ const cssSource = cssSourcesByPath.get(sourcePath);
149
+ if (!cssSource?.cssModuleEvidence || cssSource.cssModuleEvidenceSource !== 'inferred-source') return undefined;
150
+ return cssSource;
151
+ }
152
+
153
+ function compositionGraphEdge(composition, extra) {
154
+ return {
155
+ sourcePath: extra.sourcePath,
156
+ localName: composition.localName,
157
+ names: [...(composition.names ?? [])],
158
+ source: composition.source,
159
+ sourceKind: extra.sourceKind,
160
+ targetSourcePath: extra.targetSourcePath,
161
+ targetSourceHash: extra.targetSourceHash,
162
+ targetModuleHash: extra.targetModuleHash,
163
+ compositionHash: composition.compositionHash
164
+ };
165
+ }
166
+
167
+ function resolveRelativeCssSourcePath(sourcePath, specifier) {
168
+ if (!sourcePath || !specifier || !String(specifier).startsWith('.')) return undefined;
169
+ const cleanSpecifier = String(specifier).split(/[?#]/)[0];
170
+ const parts = String(sourcePath).split('/');
171
+ parts.pop();
172
+ for (const part of cleanSpecifier.split('/')) {
173
+ if (!part || part === '.') continue;
174
+ if (part === '..') {
175
+ if (!parts.length) return undefined;
176
+ parts.pop();
177
+ continue;
178
+ }
179
+ parts.push(part);
180
+ }
181
+ return parts.join('/');
182
+ }
183
+
184
+ function cssModuleCompositions(evidence) {
185
+ return arrayValue(evidence?.compositions);
186
+ }
187
+
188
+ function cssModuleIcssImports(evidence) {
189
+ return [
190
+ ...arrayValue(evidence?.icssImports),
191
+ ...arrayValue(evidence?.icss?.imports)
192
+ ];
193
+ }
194
+
195
+ function cssModuleIcssExports(evidence) {
196
+ return [
197
+ ...arrayValue(evidence?.icssExports),
198
+ ...arrayValue(evidence?.icss?.exports)
199
+ ];
200
+ }
201
+
202
+ function cssModuleExportNames(evidence) {
203
+ return uniqueSortedStrings([
204
+ ...arrayValue(evidence?.exportNames),
205
+ ...arrayValue(evidence?.localClassNames),
206
+ ...arrayValue(evidence?.classNames),
207
+ ...cssModuleExportRecordNames(evidence?.exports),
208
+ ...objectKeys(evidence?.exports),
209
+ ...objectKeys(evidence?.generatedClassNameMap),
210
+ ...objectKeys(evidence?.classMap)
211
+ ]);
212
+ }
213
+
214
+ function cssModuleIcssExportNames(evidence) {
215
+ return uniqueSortedStrings([
216
+ ...arrayValue(evidence?.icssExportNames),
217
+ ...cssModuleExportRecordNames(evidence?.icssExports),
218
+ ...objectKeys(evidence?.icssExports),
219
+ ...cssModuleExportRecordNames(evidence?.icss?.exports),
220
+ ...objectKeys(evidence?.icss?.exports)
221
+ ]);
222
+ }
223
+
224
+ function cssModuleExportRecordNames(value) {
225
+ return Array.isArray(value)
226
+ ? value.map((entry) => entry?.name ?? entry?.localName ?? entry?.exportedName).filter(Boolean)
227
+ : [];
228
+ }
229
+
230
+ function cssModuleProofGapsWithout(proofGaps, codes) {
231
+ const remove = new Set(codes);
232
+ return arrayValue(proofGaps).filter((gap) => !remove.has(gap?.code));
233
+ }
234
+
235
+ function sortedValues(map) {
236
+ return [...map.values()].sort(stableRecordCompare);
237
+ }
238
+
239
+ function stableRecordCompare(left, right) {
240
+ return JSON.stringify(left).localeCompare(JSON.stringify(right));
241
+ }
242
+
243
+ function arrayValue(value) {
244
+ return Array.isArray(value) ? value : [];
245
+ }
246
+
247
+ function objectKeys(value) {
248
+ return value && typeof value === 'object' && !Array.isArray(value) ? Object.keys(value) : [];
249
+ }
250
+
251
+ function uniqueSortedStrings(values) {
252
+ return [...new Set(values.filter((value) => typeof value === 'string' && value.length > 0))].sort();
253
+ }
254
+
255
+ export { withProjectCssModuleDependencyGraphs };
@@ -54,7 +54,9 @@ function cssModuleImportBindingRecord(edge, index, documentsById, cssSourcesByPa
54
54
  generatedClassNameMapHash: cssModuleEvidence?.generatedClassNameMapHash ?? cssModuleGeneratedClassNameMapHash(cssModuleEvidence),
55
55
  jsTsUseSiteGraphHash: cssModuleEvidence?.jsTsUseSiteGraphHash,
56
56
  cssModuleCompositionGraphHash: cssModuleEvidence?.cssModuleCompositionGraphHash,
57
+ cssModuleCompositionGraphSource: cssModuleEvidence?.cssModuleCompositionGraphSource,
57
58
  icssGraphHash: cssModuleEvidence?.icssGraphHash,
59
+ icssGraphSource: cssModuleEvidence?.icssGraphSource,
58
60
  bundlerTransformHash: cssSource?.bundlerTransformHash,
59
61
  sourceMapProofHash: cssSource?.sourceMapProofHash,
60
62
  signatureHash
@@ -213,6 +215,10 @@ function cssModuleUseSiteGraphRecord(cssModuleSourcePath, bindings, graphUseSite
213
215
  blockerCount: graphBlockers.length,
214
216
  generatedClassNameMapHash: bindings.find((binding) => binding.generatedClassNameMapHash)?.generatedClassNameMapHash,
215
217
  cssModuleExportNamesHash: bindings.find((binding) => binding.cssModuleExportNamesHash)?.cssModuleExportNamesHash,
218
+ cssModuleCompositionGraphHash: bindings.find((binding) => binding.cssModuleCompositionGraphHash)?.cssModuleCompositionGraphHash,
219
+ cssModuleCompositionGraphSource: bindings.find((binding) => binding.cssModuleCompositionGraphSource)?.cssModuleCompositionGraphSource,
220
+ icssGraphHash: bindings.find((binding) => binding.icssGraphHash)?.icssGraphHash,
221
+ icssGraphSource: bindings.find((binding) => binding.icssGraphSource)?.icssGraphSource,
216
222
  bundlerTransformHash: bindings.find((binding) => binding.bundlerTransformHash)?.bundlerTransformHash,
217
223
  sourceMapProofHash: bindings.find((binding) => binding.sourceMapProofHash)?.sourceMapProofHash,
218
224
  jsTsUseSiteGraphHash,
@@ -15,6 +15,7 @@ import {
15
15
  cssModuleTransformBlockers,
16
16
  cssModuleUseSiteGraphRecords
17
17
  } from './projectSymbolGraphCssModuleRecords.js';
18
+ import { withProjectCssModuleDependencyGraphs } from './projectSymbolGraphCssModuleDependencyGraphs.js';
18
19
  import {
19
20
  cssModuleJsxUseSites,
20
21
  cssModuleLexicalUseSites
@@ -27,10 +28,11 @@ function createProjectCssModuleGraphRecords(semanticIndex, imports, importEdges,
27
28
  const cssSourcesByPath = new Map(imports
28
29
  .map((imported) => [sourcePathForImport(imported), cssModuleSourceRecord(imported)])
29
30
  .filter(([sourcePath]) => sourcePath));
31
+ const cssSourcesWithDependencyGraphsByPath = withProjectCssModuleDependencyGraphs(cssSourcesByPath);
30
32
  const documentsById = new Map((semanticIndex?.documents ?? []).map((document) => [document.id, document]));
31
33
  const importBindings = uniqueRecords(importEdges
32
34
  .filter(isCssModuleBindingEdge)
33
- .map((edge, index) => cssModuleImportBindingRecord(edge, index, documentsById, cssSourcesByPath)));
35
+ .map((edge, index) => cssModuleImportBindingRecord(edge, index, documentsById, cssSourcesWithDependencyGraphsByPath)));
34
36
  const bindingsByLocal = groupBindingsByLocal(importBindings);
35
37
  const { useSites: lexicalUseSites, blockers: lexicalBlockers } = cssModuleLexicalUseSites(importBindings, sourceTextsByPath);
36
38
  const { useSites: jsxUseSites, blockers: jsxBlockers } = cssModuleJsxUseSites(bindingsByLocal, jsxPropRecords);
@@ -43,7 +45,7 @@ function createProjectCssModuleGraphRecords(semanticIndex, imports, importEdges,
43
45
  const missingTransformBlockers = usedImportBindings
44
46
  .flatMap((binding) => cssModuleTransformBlockers(binding));
45
47
  const missingDependencyGraphBlockers = usedImportBindings
46
- .flatMap((binding) => cssModuleDependencyGraphBlockers(binding, cssSourcesByPath));
48
+ .flatMap((binding) => cssModuleDependencyGraphBlockers(binding, cssSourcesWithDependencyGraphsByPath));
47
49
  const bindingsById = new Map(importBindings.map((binding) => [binding.id, binding]));
48
50
  const missingExportBlockers = cssModuleMissingExportBlockers(bindingsById, cssModuleUseSites);
49
51
  const cssModuleUseSiteBlockers = uniqueRecords([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.195",
3
+ "version": "0.2.197",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -63,7 +63,7 @@
63
63
  "dependencies": {
64
64
  "@shapeshift-labs/frontier-lang-c": "0.2.9",
65
65
  "@shapeshift-labs/frontier-lang-checker": "0.3.8",
66
- "@shapeshift-labs/frontier-lang-css": "^0.1.26",
66
+ "@shapeshift-labs/frontier-lang-css": "^0.1.27",
67
67
  "@shapeshift-labs/frontier-lang-html": "^0.1.16",
68
68
  "@shapeshift-labs/frontier-lang-javascript": "0.2.9",
69
69
  "@shapeshift-labs/frontier-lang-kernel": "0.3.12",