@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 first = remainder?.split('/')[0];
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
- ...(first && remainder?.includes('/') && first !== '__tests__' ? { submodule: first } : {}),
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 localDeepImport = sourceImport.specifier.match(/^#([^/]+)\/[^/]+\/.+/);
339
- if (localDeepImport &&
340
- project.policy.layers.some(({ id }) => id === localDeepImport[1])) {
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}/${file.submodule}`, { file, sourcePath });
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 [owner, { file, sourcePath }] of owners) {
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 &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.71",
3
+ "version": "0.5.0-beta.72",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",