mbeditor 0.7.2 → 0.7.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c88d7e8236553061b81b5f828261a5fdfdbf77992b8c1b46c662e49d187b3bac
4
- data.tar.gz: 5b7ae20d67ed9e1e3b63f393252dc94b001331fcc8a7073add6e767ec440ef06
3
+ metadata.gz: dd301d5fbcf6d107417270314be0561ac408505b9fc5d9c3862077ce17c68d10
4
+ data.tar.gz: 60bf4c608bf64ee929bde7c1ba537c4d07b26374e35233fdc2c0563b350eb20d
5
5
  SHA512:
6
- metadata.gz: 0e0841e9552fb15f688ca19f54767283ec338eb26b2a2476eadfc69986c62a940738538120eb3fe9ed3687ed21178710f45976747fcfcb5480694541b09f597f
7
- data.tar.gz: 96577d3f9f1293a66ec5b70fc81a322eddf11a5e50cdaef3d7965fb8d69a02411dbe0cbb6782c144f87f42aee66fd21fb731ebafd154de9155d3a24ac2e6b19b
6
+ metadata.gz: eb42152a396ec834bf84207e1e9c6a77a5a21c11d6a3c63be839c19f48856cdd08b95e3921ad6acf843a0f2d0debefc6e769ef14a1813c162d02a5912d3691cb
7
+ data.tar.gz: ffe883ef2af226e85c53978f4165c04bbe62cf83364f4a6b25bdf7cbbdcc7b52d984733b0ed549e2a978b953366153ca944f4df184c0cb69c80c40b6ad3fd1a2
data/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.4] - 2026-06-03
9
+
10
+ ### Fixed
11
+ - **Custom path reverse lookup (frontend)** — the v0.7.3 backend fix was complete, but the frontend's `resourceLabelFromPath` still returned `null` for paths under `app/` that weren't `controllers|models|views|helpers`, so custom paths like `app/assets/javascripts/…` were never recognized. Moved the custom-path check to the top of the function, matching the backend approach.
12
+
13
+ ---
14
+
15
+ ## [0.7.3] - 2026-06-03
16
+
17
+ ### Fixed
18
+ - **Custom path reverse lookup (backend)** — moved the custom-path check in `extract_resource_names` before the `case` statement so paths under `app/assets/`, `app/javascript/`, etc. are handled. Stripped `_controller`/`_model`/`_helper`/`_service` suffixes from custom-path filenames for consistent label/grouping.
19
+ - **Schema modal `self.table_name` support** — reads `self.table_name` from the model file before falling back to `ActiveSupport::Inflector.tableize`, enabling custom table names.
20
+ - **Structure.sql broader schema-prefix regex** — handles quoted schemas, non-public schemas, and no prefix.
21
+ - **PostgreSQL type coverage** — expanded `sql_type_to_rails` with full PostgreSQL type coverage (timestamptz, double precision, citext, hstore, geometric types, etc.).
22
+ - **Schema read error handling** — broadened rescue in `try_schema_rb`/`try_structure_sql` to catch encoding errors.
23
+
24
+ ---
25
+
8
26
  ## [0.7.2] - 2026-06-03
9
27
 
10
28
  ### Changed
@@ -1610,6 +1610,26 @@ var MbeditorApp = function MbeditorApp() {
1610
1610
 
1611
1611
  var resourceLabelFromPath = function(p) {
1612
1612
  if (!p) return null;
1613
+
1614
+ // Custom paths are checked first so they work regardless of top-level prefix.
1615
+ // Paths under app/assets/, app/javascript/, etc. never match standard
1616
+ // app/controllers|models|views|helpers, so the check must happen first.
1617
+ var customPaths = customPathsRef.current;
1618
+ for (var ci = 0; ci < customPaths.length; ci++) {
1619
+ var base = customPaths[ci];
1620
+ if (p.startsWith(base + '/')) {
1621
+ var rest = p.slice(base.length + 1);
1622
+ var resource = rest.split('/')[0].replace(/\.[^.]+$/, '');
1623
+ resource = resource.replace(/_(controller|model|helper|service)$/, '');
1624
+ if (resource) {
1625
+ var seg = resource.replace(/ies$/, 'y')
1626
+ .replace(/([^aeiou])es$/, '$1')
1627
+ .replace(/([^s])s$/, '$1');
1628
+ return seg.replace(/_/g, ' ').replace(/\b\w/g, function(c) { return c.toUpperCase(); });
1629
+ }
1630
+ }
1631
+ }
1632
+
1613
1633
  var parts = p.split('/');
1614
1634
  var file = parts[parts.length - 1];
1615
1635
  var name;
@@ -1624,23 +1644,9 @@ var MbeditorApp = function MbeditorApp() {
1624
1644
  else if (parts[1] === 'models') name = file.replace(/_(test|spec)\.rb$/, '');
1625
1645
  else return null;
1626
1646
  } else {
1627
- // Check custom paths
1628
- var customPaths = customPathsRef.current;
1629
- for (var ci = 0; ci < customPaths.length; ci++) {
1630
- var base = customPaths[ci];
1631
- if (p.startsWith(base + '/')) {
1632
- var rest = p.slice(base.length + 1);
1633
- var resource = rest.split('/')[0].replace(/\.[^.]+$/, '');
1634
- if (resource) {
1635
- var seg = resource.replace(/_/g, ' ').replace(/\b\w/g, function(c) { return c.toUpperCase(); });
1636
- return seg;
1637
- }
1638
- }
1639
- }
1640
1647
  return null;
1641
1648
  }
1642
1649
  var seg = (name || '').split('/').pop() || name || '';
1643
- // Normalize plural→singular so views/users and models/user share one group
1644
1650
  seg = seg.replace(/ies$/, 'y')
1645
1651
  .replace(/([^aeiou])es$/, '$1')
1646
1652
  .replace(/([^s])s$/, '$1');
@@ -124,6 +124,20 @@ module Mbeditor
124
124
  parts = relative_path.to_s.split("/")
125
125
  return nil unless parts.length >= 2
126
126
 
127
+ # Custom paths are checked first so they work regardless of top-level prefix.
128
+ # Paths under app/assets/, app/javascript/, etc. never reach the standard
129
+ # "app" branch, so the check must happen before the case statement.
130
+ Array(custom_paths).each do |base|
131
+ base = base.to_s.strip
132
+ next if base.empty?
133
+ next unless relative_path.start_with?("#{base}/")
134
+ rest = relative_path.delete_prefix("#{base}/")
135
+ resource = rest.split('/').first.to_s.sub(/\.[^.]+$/, '') # first segment, no extension
136
+ resource = resource.sub(/_(controller|model|helper|service)$/, '') # strip Rails suffixes
137
+ next if resource.empty?
138
+ return [pluralize(resource), singularize(resource)]
139
+ end
140
+
127
141
  case parts[0]
128
142
  when "app"
129
143
  case parts[1]
@@ -230,16 +244,6 @@ module Mbeditor
230
244
  end
231
245
 
232
246
  else
233
- # Custom path fallback — must be last
234
- Array(custom_paths).each do |base|
235
- base = base.to_s.strip
236
- next if base.empty?
237
- next unless relative_path.start_with?("#{base}/")
238
- rest = relative_path.delete_prefix("#{base}/")
239
- resource = rest.split('/').first.to_s.sub(/\.[^.]+$/, '') # first path segment, no extension
240
- next if resource.empty?
241
- return [pluralize(resource), singularize(resource)]
242
- end
243
247
  nil
244
248
  end
245
249
  end
@@ -40,8 +40,25 @@ module Mbeditor
40
40
  private
41
41
 
42
42
  # "User" → "users", "OrderItem" → "order_items", "Order Item" → "order_items"
43
+ # Also checks the model file for an explicit `self.table_name = "..."` declaration.
43
44
  def derive_table_name(model_name)
44
45
  normalized = model_name.delete(" ")
46
+
47
+ # Check model file for an explicit table_name override
48
+ singular = ActiveSupport::Inflector.underscore(normalized)
49
+ model_file = File.join(@workspace_root, "app", "models", "#{singular}.rb")
50
+ if File.exist?(model_file)
51
+ begin
52
+ source = File.read(model_file, encoding: "utf-8")
53
+ # Matches: self.table_name = "name" or = :name or = 'name'
54
+ if (m = source.match(/self\.table_name\s*=\s*[:"']([^"'\s]+)["']?/))
55
+ return m[1]
56
+ end
57
+ rescue StandardError
58
+ # fall through to default derivation
59
+ end
60
+ end
61
+
45
62
  ActiveSupport::Inflector.tableize(normalized)
46
63
  end
47
64
 
@@ -53,7 +70,7 @@ module Mbeditor
53
70
  begin
54
71
  content = File.read(schema_path, encoding: "utf-8")
55
72
  parse_schema_rb(content, table_name)
56
- rescue Errno::ENOENT, Errno::EACCES => e
73
+ rescue StandardError => e
57
74
  Rails.logger.debug("SchemaService: failed to read #{schema_path}: #{e.message}")
58
75
  nil
59
76
  end
@@ -67,7 +84,7 @@ module Mbeditor
67
84
  begin
68
85
  content = File.read(schema_path, encoding: "utf-8")
69
86
  parse_structure_sql(content, table_name)
70
- rescue Errno::ENOENT, Errno::EACCES => e
87
+ rescue StandardError => e
71
88
  Rails.logger.debug("SchemaService: failed to read #{schema_path}: #{e.message}")
72
89
  nil
73
90
  end
@@ -145,11 +162,13 @@ module Mbeditor
145
162
  # Handles: PostgreSQL, MySQL, SQLite with quoted/unquoted names
146
163
  # Ends with different delimiters: ); ENGINE...; or just );
147
164
  quoted_name = Regexp.escape(table_name)
165
+ # Schema prefix pattern: matches public., "public"., myschema., "myschema". or nothing.
166
+ schema_prefix = /(?:(?:"[^"]+"|`[^`]+`|\w+)\.)?/
148
167
  patterns = [
149
- # PostgreSQL with public schema: CREATE TABLE public."users" ( ... );
150
- /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:public\.)?["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*;/mi,
151
- # MySQL with ENGINE: CREATE TABLE `users` ( ... ) ENGINE=...;
152
- /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|DEFAULT)/mi
168
+ # PostgreSQL: CREATE TABLE [schema.]table ( ... );
169
+ /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?#{schema_prefix}["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*;/mi,
170
+ # MySQL: CREATE TABLE [schema.]`table` ( ... ) ENGINE=...;
171
+ /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?#{schema_prefix}["`]?#{quoted_name}["`]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|DEFAULT)/mi
153
172
  ]
154
173
 
155
174
  table_def = nil
@@ -240,6 +259,9 @@ module Mbeditor
240
259
  type_map = {
241
260
  'integer' => 'integer',
242
261
  'int' => 'integer',
262
+ 'int4' => 'integer',
263
+ 'int2' => 'integer',
264
+ 'int8' => 'bigint',
243
265
  'bigint' => 'bigint',
244
266
  'smallint' => 'integer',
245
267
  'bigserial' => 'bigint',
@@ -247,21 +269,50 @@ module Mbeditor
247
269
  'varchar' => 'string',
248
270
  'character varying' => 'string',
249
271
  'character' => 'string',
272
+ 'char' => 'string',
250
273
  'text' => 'text',
274
+ 'citext' => 'string',
251
275
  'boolean' => 'boolean',
252
276
  'bool' => 'boolean',
253
277
  'decimal' => 'decimal',
254
278
  'numeric' => 'decimal',
279
+ 'real' => 'float',
255
280
  'float' => 'float',
281
+ 'float4' => 'float',
282
+ 'float8' => 'float',
283
+ 'double precision' => 'float',
256
284
  'double' => 'float',
285
+ 'money' => 'decimal',
257
286
  'timestamp' => 'datetime',
287
+ 'timestamp without time zone' => 'datetime',
288
+ 'timestamp with time zone' => 'datetime',
289
+ 'timestamptz' => 'datetime',
258
290
  'datetime' => 'datetime',
259
291
  'date' => 'date',
260
292
  'time' => 'time',
293
+ 'time without time zone' => 'time',
294
+ 'time with time zone' => 'time',
295
+ 'interval' => 'string',
261
296
  'json' => 'json',
262
297
  'jsonb' => 'jsonb',
263
298
  'uuid' => 'uuid',
264
- 'bytea' => 'binary'
299
+ 'bytea' => 'binary',
300
+ 'bit' => 'string',
301
+ 'bit varying' => 'string',
302
+ 'inet' => 'string',
303
+ 'cidr' => 'string',
304
+ 'macaddr' => 'string',
305
+ 'xml' => 'string',
306
+ 'hstore' => 'hstore',
307
+ 'tsvector' => 'string',
308
+ 'ltree' => 'string',
309
+ 'point' => 'string',
310
+ 'line' => 'string',
311
+ 'lseg' => 'string',
312
+ 'box' => 'string',
313
+ 'path' => 'string',
314
+ 'polygon' => 'string',
315
+ 'circle' => 'string'
265
316
  }
266
317
 
267
318
  type_map[sql_type.downcase] || sql_type
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mbeditor
4
- VERSION = "0.7.2"
4
+ VERSION = "0.7.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbeditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Noonan