modscape 1.0.5 → 1.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modscape",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Modscape: A YAML-driven data modeling visualizer CLI",
5
5
  "repository": {
6
6
  "type": "git",
package/src/create.js ADDED
@@ -0,0 +1,45 @@
1
+ import { confirm } from '@inquirer/prompts';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ export async function createModel(filePath) {
9
+ // 1. Extension Handling
10
+ if (!filePath.endsWith('.yaml') && !filePath.endsWith('.yml')) {
11
+ filePath += '.yaml';
12
+ }
13
+
14
+ const absolutePath = path.resolve(process.cwd(), filePath);
15
+ const dir = path.dirname(absolutePath);
16
+
17
+ // 2. Recursive Directory Creation
18
+ if (!fs.existsSync(dir)) {
19
+ fs.mkdirSync(dir, { recursive: true });
20
+ console.log(` Created directory: ${path.relative(process.cwd(), dir)}`);
21
+ }
22
+
23
+ // 3. Overwrite Protection
24
+ if (fs.existsSync(absolutePath)) {
25
+ const overwrite = await confirm({
26
+ message: `File ${filePath} already exists. Overwrite with template?`,
27
+ default: false,
28
+ });
29
+ if (!overwrite) {
30
+ console.log(` Operation cancelled. File ${filePath} preserved.`);
31
+ return;
32
+ }
33
+ }
34
+
35
+ // 4. Template Writing
36
+ try {
37
+ const templatePath = path.join(__dirname, 'templates/default-model.yaml');
38
+ const template = fs.readFileSync(templatePath, 'utf8');
39
+ fs.writeFileSync(absolutePath, template, 'utf8');
40
+ console.log(` ✅ Successfully created new model: ${filePath}`);
41
+ console.log(` 🚀 Run 'modscape dev ${filePath}' to start modeling.`);
42
+ } catch (error) {
43
+ console.error(` ❌ Failed to create model: ${error.message}`);
44
+ }
45
+ }
package/src/index.js CHANGED
@@ -7,6 +7,7 @@ import { startDevServer } from './dev.js';
7
7
  import { build } from './build.js';
8
8
  import { initProject } from './init.js';
9
9
  import { exportModel } from './export.js';
10
+ import { createModel } from './create.js';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
  const VISUALIZER_PATH = path.resolve(__dirname, '../visualizer');
@@ -15,7 +16,7 @@ const program = new Command();
15
16
  program
16
17
  .name('modscape')
17
18
  .description('Modscape: A YAML-driven data modeling visualizer CLI')
18
- .version('1.0.5');
19
+ .version('1.0.7');
19
20
 
20
21
  program
21
22
  .command('init')
@@ -28,6 +29,14 @@ program
28
29
  initProject(options);
29
30
  });
30
31
 
32
+ program
33
+ .command('new')
34
+ .description('Create a new YAML model file from template')
35
+ .argument('<path>', 'path to the new YAML file')
36
+ .action((path) => {
37
+ createModel(path);
38
+ });
39
+
31
40
  program
32
41
  .command('dev')
33
42
  .description('Start the development visualizer with local YAML files or directories')
@@ -0,0 +1,61 @@
1
+ # Modscape Data Model
2
+ # Use 'modscape dev <filename>' to visualize and edit this model.
3
+
4
+ domains:
5
+ - id: sample_domain
6
+ name: Sample Domain
7
+ color: "rgba(59, 130, 246, 0.1)"
8
+ description: "A logical grouping of related business entities."
9
+ tables: [source_table, derived_table]
10
+
11
+ tables:
12
+ - id: source_table
13
+ name: Source Table
14
+ logical_name: "Original Business Record"
15
+ physical_name: "raw_source_table"
16
+ appearance:
17
+ type: table
18
+ icon: "📋"
19
+ columns:
20
+ - id: id
21
+ logical: { name: ID, type: Int, isPrimaryKey: true }
22
+ physical: { name: id, type: BIGINT }
23
+ - id: name
24
+ logical: { name: Name, type: String }
25
+ physical: { name: name, type: VARCHAR(255) }
26
+ sampleData:
27
+ - [id, name]
28
+ - [1, "Example Record A"]
29
+ - [2, "Example Record B"]
30
+
31
+ - id: derived_table
32
+ name: Derived Mart
33
+ logical_name: "Processed Analytics Summary"
34
+ physical_name: "mart_derived_summary"
35
+ appearance:
36
+ type: mart
37
+ icon: "📈"
38
+ lineage:
39
+ upstream: [source_table] # Lineage: Defines the flow of data (dashed arrows)
40
+ columns:
41
+ - id: id
42
+ logical: { name: ID, type: Int, isPrimaryKey: true }
43
+ physical: { name: id, type: BIGINT }
44
+ - id: source_id
45
+ logical: { name: Source ID, type: Int, isForeignKey: true }
46
+ physical: { name: source_id, type: BIGINT }
47
+ - id: summary_value
48
+ logical: { name: Value, type: Decimal, additivity: fully }
49
+ physical: { name: total_val, type: NUMBER(18,2) }
50
+ sampleData:
51
+ - [id, source_id, summary_value]
52
+ - [101, 1, 150.50]
53
+ - [102, 2, 300.75]
54
+
55
+ relationships:
56
+ # Relationships: Defines Entity-Relationship connections (solid lines with 1:M badges)
57
+ - from: { table: source_table, column: id }
58
+ to: { table: derived_table, column: source_id }
59
+ type: one-to-many
60
+
61
+ lineage: [] # Note: Table-level lineage is also supported here, or inside tables[].lineage
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "visualizer",
3
3
  "private": true,
4
- "version": "1.0.5",
4
+ "version": "1.0.7",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",