@astrale-os/sdk 0.5.0-beta.71 → 0.5.0-beta.72
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0-beta.72](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.71...sdk-v0.5.0-beta.72) (2026-08-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **linter:** recognize nested schema modules ([#316](https://github.com/astrale-os/sdk/issues/316)) ([d9ad841](https://github.com/astrale-os/sdk/commit/d9ad84165103ed7741f11801ea740476109b99b3))
|
|
9
|
+
|
|
3
10
|
## [0.5.0-beta.71](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.70...sdk-v0.5.0-beta.71) (2026-08-28)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -206,7 +206,7 @@ async function admitFile(root, absolutePath, policy) {
|
|
|
206
206
|
const source = ts.createSourceFile(absolutePath, text, ts.ScriptTarget.Latest, true, scriptKind(absolutePath));
|
|
207
207
|
const layer = policy.layers.find(({ sourcePath }) => path.startsWith(sourcePath));
|
|
208
208
|
const remainder = layer ? path.slice(layer.sourcePath.length) : undefined;
|
|
209
|
-
const
|
|
209
|
+
const submodule = semanticSubmodule(layer?.id, remainder);
|
|
210
210
|
const role = sourceRole(path, layer?.id);
|
|
211
211
|
return Object.freeze({
|
|
212
212
|
absolutePath,
|
|
@@ -215,11 +215,23 @@ async function admitFile(root, absolutePath, policy) {
|
|
|
215
215
|
source,
|
|
216
216
|
role,
|
|
217
217
|
...(layer ? { layer: layer.id } : {}),
|
|
218
|
-
...(
|
|
218
|
+
...(submodule ? { submodule } : {}),
|
|
219
219
|
imports: Object.freeze(collectImports(source)),
|
|
220
220
|
dependencyIssues: Object.freeze(collectDependencyIssues(source)),
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
|
+
function semanticSubmodule(layer, remainder) {
|
|
224
|
+
if (!remainder)
|
|
225
|
+
return undefined;
|
|
226
|
+
const segments = remainder.split('/');
|
|
227
|
+
const first = segments[0];
|
|
228
|
+
if (!first || first === '__tests__' || segments.length < 2)
|
|
229
|
+
return undefined;
|
|
230
|
+
if (layer === 'schema' && first === 'modules' && segments.length >= 3 && segments[1]) {
|
|
231
|
+
return `modules/${segments[1]}`;
|
|
232
|
+
}
|
|
233
|
+
return first;
|
|
234
|
+
}
|
|
223
235
|
function sourceRole(path, layer) {
|
|
224
236
|
const segments = path.split('/');
|
|
225
237
|
if (segments.includes('__tests__') || /\.(?:test|spec|bench|perf)\.[cm]?[jt]sx?$/.test(path)) {
|
|
@@ -335,16 +335,24 @@ export const globalRules = [
|
|
|
335
335
|
const evidence = [];
|
|
336
336
|
for (const file of production(project)) {
|
|
337
337
|
for (const sourceImport of file.imports) {
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
338
|
+
const target = resolveProjectImport(project, file, sourceImport.specifier);
|
|
339
|
+
const localAliasSegments = sourceImport.specifier.startsWith('#')
|
|
340
|
+
? sourceImport.specifier.split('/')
|
|
341
|
+
: [];
|
|
342
|
+
const aliasLayer = localAliasSegments[0]?.slice(1);
|
|
343
|
+
const nestedSchemaModuleFacade = aliasLayer === 'schema' &&
|
|
344
|
+
localAliasSegments[1] === 'modules' &&
|
|
345
|
+
localAliasSegments.length === 3;
|
|
346
|
+
if (!target &&
|
|
347
|
+
localAliasSegments.length >= 3 &&
|
|
348
|
+
!nestedSchemaModuleFacade &&
|
|
349
|
+
project.policy.layers.some(({ id }) => id === aliasLayer)) {
|
|
341
350
|
evidence.push(violation(file, sourceImport.node, `Import ${sourceImport.specifier} reaches private source; use the semantic submodule facade.`));
|
|
342
351
|
}
|
|
343
352
|
if (isForeignDomain(sourceImport.specifier) &&
|
|
344
353
|
isDeepPackageImport(sourceImport.specifier)) {
|
|
345
354
|
evidence.push(violation(file, sourceImport.node, `Foreign Domain import ${sourceImport.specifier} bypasses ${packageRoot(sourceImport.specifier)}.`));
|
|
346
355
|
}
|
|
347
|
-
const target = resolveProjectImport(project, file, sourceImport.specifier);
|
|
348
356
|
if (!file.layer ||
|
|
349
357
|
!target?.layer ||
|
|
350
358
|
file.layer !== target.layer ||
|
|
@@ -10,12 +10,16 @@ export const testRules = [
|
|
|
10
10
|
if (file.layer && file.layer !== 'tests' && file.submodule) {
|
|
11
11
|
const sourcePath = project.policy.layers.find(({ id }) => id === file.layer)?.sourcePath;
|
|
12
12
|
if (sourcePath !== undefined) {
|
|
13
|
-
owners.set(`${file.layer}
|
|
13
|
+
owners.set(`${file.layer}\0${file.submodule}`, {
|
|
14
|
+
file,
|
|
15
|
+
layer: file.layer,
|
|
16
|
+
sourcePath,
|
|
17
|
+
submodule: file.submodule,
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
|
-
for (const
|
|
18
|
-
const [layer, submodule] = owner.split('/');
|
|
22
|
+
for (const { file, layer, sourcePath, submodule } of owners.values()) {
|
|
19
23
|
const physicalOwner = `${sourcePath}${submodule}`;
|
|
20
24
|
const hasFocusedEvidence = project.files.some((candidate) => candidate.layer === layer &&
|
|
21
25
|
candidate.submodule === submodule &&
|