@domainlang/language 0.1.20 → 0.1.82

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.
Files changed (110) hide show
  1. package/out/domain-lang-module.d.ts +0 -2
  2. package/out/domain-lang-module.js +3 -11
  3. package/out/domain-lang-module.js.map +1 -1
  4. package/out/generated/ast.d.ts +19 -8
  5. package/out/generated/ast.js +10 -1
  6. package/out/generated/ast.js.map +1 -1
  7. package/out/generated/grammar.d.ts +1 -1
  8. package/out/generated/grammar.js +123 -28
  9. package/out/generated/grammar.js.map +1 -1
  10. package/out/generated/module.d.ts +1 -1
  11. package/out/generated/module.js +1 -1
  12. package/out/index.d.ts +0 -3
  13. package/out/index.js +0 -5
  14. package/out/index.js.map +1 -1
  15. package/out/lsp/hover/domain-lang-hover.js +4 -0
  16. package/out/lsp/hover/domain-lang-hover.js.map +1 -1
  17. package/out/sdk/index.d.ts +1 -1
  18. package/out/sdk/loader-node.d.ts +3 -7
  19. package/out/sdk/loader-node.js +9 -24
  20. package/out/sdk/loader-node.js.map +1 -1
  21. package/out/sdk/types.d.ts +21 -0
  22. package/out/services/dependency-analyzer.d.ts +39 -3
  23. package/out/services/dependency-analyzer.js +47 -22
  24. package/out/services/dependency-analyzer.js.map +1 -1
  25. package/out/services/dependency-resolver.d.ts +45 -68
  26. package/out/services/dependency-resolver.js +43 -243
  27. package/out/services/dependency-resolver.js.map +1 -1
  28. package/out/services/git-url-resolver.browser.d.ts +12 -4
  29. package/out/services/git-url-resolver.browser.js +1 -5
  30. package/out/services/git-url-resolver.browser.js.map +1 -1
  31. package/out/services/git-url-resolver.d.ts +56 -22
  32. package/out/services/git-url-resolver.js +36 -70
  33. package/out/services/git-url-resolver.js.map +1 -1
  34. package/out/services/governance-validator.d.ts +37 -1
  35. package/out/services/governance-validator.js +10 -4
  36. package/out/services/governance-validator.js.map +1 -1
  37. package/out/services/import-resolver.d.ts +6 -65
  38. package/out/services/import-resolver.js +5 -223
  39. package/out/services/import-resolver.js.map +1 -1
  40. package/out/services/performance-optimizer.d.ts +1 -1
  41. package/out/services/workspace-manager.d.ts +10 -57
  42. package/out/services/workspace-manager.js +21 -187
  43. package/out/services/workspace-manager.js.map +1 -1
  44. package/out/syntaxes/domain-lang.monarch.js +1 -1
  45. package/out/syntaxes/domain-lang.monarch.js.map +1 -1
  46. package/out/utils/import-utils.d.ts +12 -4
  47. package/out/utils/import-utils.js +135 -35
  48. package/out/utils/import-utils.js.map +1 -1
  49. package/out/validation/constants.d.ts +0 -103
  50. package/out/validation/constants.js +1 -140
  51. package/out/validation/constants.js.map +1 -1
  52. package/out/validation/domain.js +1 -46
  53. package/out/validation/domain.js.map +1 -1
  54. package/out/validation/import.d.ts +22 -46
  55. package/out/validation/import.js +85 -187
  56. package/out/validation/import.js.map +1 -1
  57. package/out/validation/maps.js +6 -10
  58. package/out/validation/maps.js.map +1 -1
  59. package/out/validation/metadata.js +1 -5
  60. package/out/validation/metadata.js.map +1 -1
  61. package/package.json +6 -8
  62. package/src/domain-lang-module.ts +6 -18
  63. package/src/domain-lang.langium +12 -7
  64. package/src/generated/ast.ts +20 -7
  65. package/src/generated/grammar.ts +123 -28
  66. package/src/generated/module.ts +1 -1
  67. package/src/index.ts +0 -7
  68. package/src/lsp/hover/domain-lang-hover.ts +2 -0
  69. package/src/sdk/index.ts +2 -0
  70. package/src/sdk/loader-node.ts +9 -29
  71. package/src/sdk/types.ts +23 -0
  72. package/src/services/dependency-analyzer.ts +84 -24
  73. package/src/services/dependency-resolver.ts +84 -301
  74. package/src/services/git-url-resolver.browser.ts +14 -9
  75. package/src/services/git-url-resolver.ts +93 -86
  76. package/src/services/governance-validator.ts +47 -5
  77. package/src/services/import-resolver.ts +8 -270
  78. package/src/services/performance-optimizer.ts +1 -1
  79. package/src/services/workspace-manager.ts +46 -237
  80. package/src/syntaxes/domain-lang.monarch.ts +1 -1
  81. package/src/utils/import-utils.ts +160 -38
  82. package/src/validation/constants.ts +1 -181
  83. package/src/validation/domain.ts +1 -54
  84. package/src/validation/import.ts +104 -228
  85. package/src/validation/maps.ts +6 -10
  86. package/src/validation/metadata.ts +1 -5
  87. package/out/lsp/domain-lang-code-actions.d.ts +0 -55
  88. package/out/lsp/domain-lang-code-actions.js +0 -143
  89. package/out/lsp/domain-lang-code-actions.js.map +0 -1
  90. package/out/lsp/domain-lang-workspace-manager.d.ts +0 -21
  91. package/out/lsp/domain-lang-workspace-manager.js +0 -93
  92. package/out/lsp/domain-lang-workspace-manager.js.map +0 -1
  93. package/out/lsp/manifest-diagnostics.d.ts +0 -82
  94. package/out/lsp/manifest-diagnostics.js +0 -230
  95. package/out/lsp/manifest-diagnostics.js.map +0 -1
  96. package/out/services/semver.d.ts +0 -98
  97. package/out/services/semver.js +0 -195
  98. package/out/services/semver.js.map +0 -1
  99. package/out/services/types.d.ts +0 -340
  100. package/out/services/types.js +0 -46
  101. package/out/services/types.js.map +0 -1
  102. package/out/validation/manifest.d.ts +0 -144
  103. package/out/validation/manifest.js +0 -327
  104. package/out/validation/manifest.js.map +0 -1
  105. package/src/lsp/domain-lang-code-actions.ts +0 -189
  106. package/src/lsp/domain-lang-workspace-manager.ts +0 -104
  107. package/src/lsp/manifest-diagnostics.ts +0 -290
  108. package/src/services/semver.ts +0 -213
  109. package/src/services/types.ts +0 -415
  110. package/src/validation/manifest.ts +0 -439
@@ -13,13 +13,66 @@
13
13
  import { URI } from 'langium';
14
14
  import path from 'node:path';
15
15
  import fs from 'node:fs/promises';
16
+ import os from 'node:os';
16
17
  import { exec } from 'node:child_process';
17
18
  import { promisify } from 'node:util';
18
19
  import YAML from 'yaml';
19
- import type { GitImportInfo, ResolvingPackage, LockFile } from './types.js';
20
20
 
21
21
  const execAsync = promisify(exec);
22
22
 
23
+ /**
24
+ * Parsed git import with repository-level information.
25
+ */
26
+ export interface GitImportInfo {
27
+ /** Original import string */
28
+ original: string;
29
+ /** Git platform (github, gitlab, bitbucket, or generic) */
30
+ platform: 'github' | 'gitlab' | 'bitbucket' | 'generic';
31
+ /** Repository owner/organization */
32
+ owner: string;
33
+ /** Repository name */
34
+ repo: string;
35
+ /** Version (tag, branch, or commit hash) */
36
+ version: string;
37
+ /** Full git repository URL */
38
+ repoUrl: string;
39
+ /** Package main entry point (from dlang.toml or default index.dlang) */
40
+ entryPoint: string;
41
+ }
42
+
43
+ /**
44
+ * Package metadata from model.yaml
45
+ */
46
+ export interface PackageMetadata {
47
+ name?: string;
48
+ version?: string;
49
+ main?: string; // Entry point file (legacy field name for compatibility)
50
+ entry?: string; // Entry point file (preferred field name)
51
+ exports?: Record<string, string>;
52
+ dependencies?: Record<string, string>; // name → version constraint
53
+ }
54
+
55
+ /**
56
+ * Lock file format (dlang.lock)
57
+ *
58
+ * Pins exact versions and commit hashes for all dependencies
59
+ * in the dependency tree. Ensures reproducible builds.
60
+ */
61
+ export interface LockFile {
62
+ version: string; // Lock file format version (currently "1")
63
+ dependencies: Record<string, LockedDependency>; // package name → locked info
64
+ }
65
+
66
+ /**
67
+ * A single locked dependency with pinned version and commit.
68
+ */
69
+ export interface LockedDependency {
70
+ version: string; // Resolved semantic version
71
+ resolved: string; // Full git URL
72
+ commit: string; // Exact commit hash (content-addressable)
73
+ integrity?: string; // Optional SHA-256 hash for verification
74
+ }
75
+
23
76
  /**
24
77
  * Parses import URLs into structured git import information.
25
78
  *
@@ -68,10 +121,7 @@ export class GitUrlParser {
68
121
  return this.parseFullUrl(importStr);
69
122
  }
70
123
 
71
- throw new Error(
72
- `Invalid git import URL: '${importStr}'.\n` +
73
- `Hint: Use 'owner/repo' or 'owner/repo@version' format (e.g., 'domainlang/core@v1.0.0').`
74
- );
124
+ throw new Error(`Invalid git import URL: ${importStr}`);
75
125
  }
76
126
 
77
127
  /**
@@ -87,10 +137,7 @@ export class GitUrlParser {
87
137
  private static parseGitHubShorthand(importStr: string): GitImportInfo {
88
138
  const match = importStr.match(/^([a-zA-Z0-9-]+)\/([a-zA-Z0-9-_.]+)(?:@([^/]+))?$/);
89
139
  if (!match) {
90
- throw new Error(
91
- `Invalid GitHub shorthand format: '${importStr}'.\n` +
92
- `Hint: Use 'owner/repo' or 'owner/repo@version' format.`
93
- );
140
+ throw new Error(`Invalid GitHub shorthand format: ${importStr}`);
94
141
  }
95
142
 
96
143
  const [, owner, repo, version] = match;
@@ -103,7 +150,7 @@ export class GitUrlParser {
103
150
  repo,
104
151
  version: resolvedVersion,
105
152
  repoUrl: `https://github.com/${owner}/${repo}`,
106
- entryPoint: 'index.dlang', // Default, will be resolved from model.yaml
153
+ entryPoint: 'index.dlang', // Default, will be resolved from dlang.toml
107
154
  };
108
155
  }
109
156
 
@@ -184,14 +231,7 @@ export class GitUrlParser {
184
231
  };
185
232
  }
186
233
 
187
- throw new Error(
188
- `Unsupported git URL format: '${importStr}'.\n` +
189
- `Supported formats:\n` +
190
- ` • owner/repo (GitHub shorthand)\n` +
191
- ` • owner/repo@version\n` +
192
- ` • https://github.com/owner/repo\n` +
193
- ` • https://gitlab.com/owner/repo`
194
- );
234
+ throw new Error(`Unsupported git URL format: ${importStr}`);
195
235
  }
196
236
  }
197
237
 
@@ -199,25 +239,18 @@ export class GitUrlParser {
199
239
  * Resolves git repository imports to local entry point files.
200
240
  *
201
241
  * Implements a content-addressable cache:
202
- * - Cache location: .dlang/packages/ (project-local, per PRS-010)
203
- * - Cache key: {owner}/{repo}/{commit-hash}
242
+ * - Cache location: ~/.dlang/cache/
243
+ * - Cache key: platform/owner/repo/commit-hash
204
244
  * - Downloads entire repository on first use
205
- * - Reads model.yaml to find entry point
245
+ * - Reads dlang.toml to find entry point
206
246
  * - Returns URI to entry point file
207
247
  */
208
248
  export class GitUrlResolver {
209
249
  private cacheDir: string;
210
250
  private lockFile?: LockFile;
211
251
 
212
- /**
213
- * Creates a GitUrlResolver with a project-local cache directory.
214
- *
215
- * @param cacheDir - The cache directory path. Per PRS-010, this should be
216
- * the project's `.dlang/packages/` directory for isolation
217
- * and reproducibility (like node_modules).
218
- */
219
- constructor(cacheDir: string) {
220
- this.cacheDir = cacheDir;
252
+ constructor(cacheDir?: string) {
253
+ this.cacheDir = cacheDir || path.join(os.homedir(), '.dlang', 'cache');
221
254
  }
222
255
 
223
256
  /**
@@ -242,13 +275,13 @@ export class GitUrlResolver {
242
275
  * 3. Resolve version to commit hash (if not locked)
243
276
  * 4. Check cache
244
277
  * 5. Download repository if not cached
245
- * 6. Read model.yaml to find entry point
278
+ * 6. Read dlang.toml to find entry point
246
279
  * 7. Return URI to entry point file
247
280
  *
248
281
  * @param importUrl - The git import URL
249
282
  * @returns URI to the package's entry point file
250
283
  */
251
- async resolve(importUrl: string, options: { allowNetwork?: boolean } = {}): Promise<URI> {
284
+ async resolve(importUrl: string): Promise<URI> {
252
285
  const gitInfo = GitUrlParser.parse(importUrl);
253
286
 
254
287
  // Check lock file for pinned version (handles transitive dependencies)
@@ -259,15 +292,7 @@ export class GitUrlResolver {
259
292
  // Use locked commit hash (reproducible build)
260
293
  commitHash = this.lockFile.dependencies[packageKey].commit;
261
294
  } else {
262
- // No lock file entry - need to resolve dynamically
263
- if (options.allowNetwork === false) {
264
- // LSP mode: cannot perform network operations
265
- throw new Error(
266
- `Dependency '${packageKey}' not installed.\n` +
267
- `Hint: Run 'dlang install' to fetch dependencies and generate model.lock.`
268
- );
269
- }
270
- // CLI/dev mode: resolve version via network
295
+ // Resolve version dynamically (development mode or missing lock)
271
296
  commitHash = await this.resolveCommit(gitInfo);
272
297
  }
273
298
 
@@ -275,13 +300,6 @@ export class GitUrlResolver {
275
300
  const cachedPath = this.getCachePath(gitInfo, commitHash);
276
301
 
277
302
  if (!(await this.existsInCache(cachedPath))) {
278
- if (options.allowNetwork === false) {
279
- throw new Error(
280
- `Dependency '${packageKey}' not installed.\n` +
281
- `Hint: Run 'dlang install' to fetch dependencies.`
282
- );
283
- }
284
-
285
303
  // Download repository
286
304
  await this.downloadRepo(gitInfo, commitHash, cachedPath);
287
305
  }
@@ -293,8 +311,7 @@ export class GitUrlResolver {
293
311
  // Verify entry point exists
294
312
  if (!(await this.existsInCache(entryFile))) {
295
313
  throw new Error(
296
- `Entry point '${entryPoint}' not found in package '${gitInfo.owner}/${gitInfo.repo}@${gitInfo.version}'.\n` +
297
- `Hint: Ensure the package has an entry point file (default: index.dlang).`
314
+ `Entry point not found: ${entryPoint} in ${gitInfo.repoUrl}@${gitInfo.version}`
298
315
  );
299
316
  }
300
317
 
@@ -311,7 +328,8 @@ export class GitUrlResolver {
311
328
  try {
312
329
  const yamlContent = await fs.readFile(yamlPath, 'utf-8');
313
330
  const metadata = this.parseYaml(yamlContent);
314
- return metadata.entry ?? 'index.dlang';
331
+ // Prefer 'entry' field, fallback to 'main' for backward compatibility
332
+ return metadata.entry || metadata.main || 'index.dlang';
315
333
  } catch {
316
334
  // No model.yaml or parse error, use default
317
335
  return 'index.dlang';
@@ -325,17 +343,19 @@ export class GitUrlResolver {
325
343
  * model:
326
344
  * entry: index.dlang
327
345
  */
328
- private parseYaml(content: string): ResolvingPackage {
346
+ private parseYaml(content: string): PackageMetadata {
329
347
  const parsed = YAML.parse(content) as {
330
348
  model?: {
331
349
  name?: string;
332
350
  version?: string;
333
351
  entry?: string;
352
+ main?: string;
334
353
  };
335
354
  };
336
355
 
337
356
  return {
338
357
  entry: parsed.model?.entry,
358
+ main: parsed.model?.main,
339
359
  name: parsed.model?.name,
340
360
  version: parsed.model?.version,
341
361
  };
@@ -361,15 +381,10 @@ export class GitUrlResolver {
361
381
  return gitInfo.version;
362
382
  }
363
383
 
364
- throw new Error(
365
- `Could not resolve version '${gitInfo.version}' for ${gitInfo.repoUrl}.\n` +
366
- `Hint: Check that the version (tag, branch, or commit) exists in the repository.`
367
- );
384
+ throw new Error(`Could not resolve version: ${gitInfo.version}`);
368
385
  } catch (error) {
369
386
  throw new Error(
370
- `Failed to resolve git version '${gitInfo.version}' for ${gitInfo.repoUrl}.\n` +
371
- `Error: ${error}\n` +
372
- `Hint: Verify the repository URL is correct and accessible.`
387
+ `Failed to resolve git version ${gitInfo.version} for ${gitInfo.repoUrl}: ${error}`
373
388
  );
374
389
  }
375
390
  }
@@ -377,14 +392,12 @@ export class GitUrlResolver {
377
392
  /**
378
393
  * Gets the local cache path for a git repository.
379
394
  *
380
- * Format: .dlang/packages/{owner}/{repo}/{version}/
381
- *
382
- * Per PRS-010: Project-local cache structure mirrors the Design Considerations
383
- * section showing `.dlang/packages/{owner}/{repo}/{version}/` layout.
395
+ * Format: ~/.dlang/cache/{platform}/{owner}/{repo}/{commit-hash}/
384
396
  */
385
397
  private getCachePath(gitInfo: GitImportInfo, commitHash: string): string {
386
398
  return path.join(
387
399
  this.cacheDir,
400
+ gitInfo.platform,
388
401
  gitInfo.owner,
389
402
  gitInfo.repo,
390
403
  commitHash
@@ -435,9 +448,7 @@ export class GitUrlResolver {
435
448
  await fs.rm(targetDir, { recursive: true, force: true });
436
449
  const message = error instanceof Error ? error.message : String(error);
437
450
  throw new Error(
438
- `Failed to download package '${gitInfo.owner}/${gitInfo.repo}@${gitInfo.version}'.\n` +
439
- `Error: ${message}\n` +
440
- `Hint: Check your network connection and verify the repository URL is correct.`
451
+ `Failed to download git repository ${gitInfo.repoUrl}@${gitInfo.version}: ${message}`
441
452
  );
442
453
  }
443
454
  }
@@ -451,8 +462,6 @@ export class GitUrlResolver {
451
462
 
452
463
  /**
453
464
  * Gets cache statistics (size, number of cached repos, etc.).
454
- *
455
- * Cache structure: .dlang/packages/{owner}/{repo}/{version}/
456
465
  */
457
466
  async getCacheStats(): Promise<{
458
467
  totalSize: number;
@@ -463,24 +472,22 @@ export class GitUrlResolver {
463
472
  let repoCount = 0;
464
473
 
465
474
  try {
466
- const owners = await fs.readdir(this.cacheDir);
467
- for (const owner of owners) {
468
- const ownerPath = path.join(this.cacheDir, owner);
469
- const ownerStat = await fs.stat(ownerPath);
470
- if (!ownerStat.isDirectory()) continue;
471
-
472
- const repos = await fs.readdir(ownerPath);
473
- for (const repo of repos) {
474
- const repoPath = path.join(ownerPath, repo);
475
- const repoStat = await fs.stat(repoPath);
476
- if (!repoStat.isDirectory()) continue;
477
-
478
- const versions = await fs.readdir(repoPath);
479
- repoCount += versions.length;
480
-
481
- for (const version of versions) {
482
- const versionPath = path.join(repoPath, version);
483
- totalSize += await this.getDirectorySize(versionPath);
475
+ const platforms = await fs.readdir(this.cacheDir);
476
+ for (const platform of platforms) {
477
+ const platformPath = path.join(this.cacheDir, platform);
478
+ const owners = await fs.readdir(platformPath);
479
+ for (const owner of owners) {
480
+ const ownerPath = path.join(platformPath, owner);
481
+ const repos = await fs.readdir(ownerPath);
482
+ for (const repo of repos) {
483
+ const repoPath = path.join(ownerPath, repo);
484
+ const commits = await fs.readdir(repoPath);
485
+ repoCount += commits.length;
486
+
487
+ for (const commit of commits) {
488
+ const commitPath = path.join(repoPath, commit);
489
+ totalSize += await this.getDirectorySize(commitPath);
490
+ }
484
491
  }
485
492
  }
486
493
  }
@@ -19,11 +19,45 @@
19
19
  * ```
20
20
  */
21
21
 
22
- import type { LockFile, GovernancePolicy, GovernanceMetadata, GovernanceViolation } from './types.js';
22
+ import type { LockFile } from './git-url-resolver.js';
23
23
  import path from 'node:path';
24
24
  import fs from 'node:fs/promises';
25
25
  import YAML from 'yaml';
26
- import { isPreRelease } from './semver.js';
26
+
27
+ export interface GovernancePolicy {
28
+ /** Allowed git domains (e.g., ['github.com/acme']) */
29
+ allowedSources?: string[];
30
+ /** Blocked packages or patterns */
31
+ blockedPackages?: string[];
32
+ /** Require stable versions only (no pre-release) */
33
+ requireStableVersions?: boolean;
34
+ /** Require team ownership metadata */
35
+ requireTeamOwnership?: boolean;
36
+ /** Allowed licenses */
37
+ allowedLicenses?: string[];
38
+ }
39
+
40
+ export interface GovernanceMetadata {
41
+ /** Team responsible for the model */
42
+ team?: string;
43
+ /** Contact email */
44
+ contact?: string;
45
+ /** Business domain */
46
+ domain?: string;
47
+ /** Compliance tags */
48
+ compliance?: string[];
49
+ }
50
+
51
+ export interface GovernanceViolation {
52
+ /** Type of violation */
53
+ type: 'blocked-source' | 'unstable-version' | 'missing-metadata' | 'license-violation';
54
+ /** Package that violates the policy */
55
+ packageKey: string;
56
+ /** Violation message */
57
+ message: string;
58
+ /** Severity: error or warning */
59
+ severity: 'error' | 'warning';
60
+ }
27
61
 
28
62
  /**
29
63
  * Validates dependencies against organizational governance policies.
@@ -73,11 +107,11 @@ export class GovernanceValidator {
73
107
 
74
108
  // Check version stability
75
109
  if (this.policy.requireStableVersions) {
76
- if (isPreRelease(locked.ref)) {
110
+ if (this.isPreReleaseVersion(locked.version)) {
77
111
  violations.push({
78
112
  type: 'unstable-version',
79
113
  packageKey,
80
- message: `Pre-release ref not allowed: ${locked.ref}`,
114
+ message: `Pre-release version not allowed: ${locked.version}`,
81
115
  severity: 'error',
82
116
  });
83
117
  }
@@ -136,7 +170,7 @@ export class GovernanceValidator {
136
170
  lines.push('Dependencies:');
137
171
 
138
172
  for (const [packageKey, locked] of Object.entries(lockFile.dependencies)) {
139
- lines.push(` - ${packageKey}@${locked.ref}`);
173
+ lines.push(` - ${packageKey}@${locked.version}`);
140
174
  lines.push(` Source: ${locked.resolved}`);
141
175
  lines.push(` Commit: ${locked.commit}`);
142
176
  }
@@ -154,6 +188,14 @@ export class GovernanceValidator {
154
188
 
155
189
  return lines.join('\n');
156
190
  }
191
+
192
+ /**
193
+ * Checks if a version is a pre-release.
194
+ */
195
+ private isPreReleaseVersion(version: string): boolean {
196
+ const clean = version.replace(/^v/, '');
197
+ return /-(alpha|beta|rc|pre|dev|snapshot)/.test(clean);
198
+ }
157
199
  }
158
200
 
159
201
  /**