ro 4.4.0 → 5.1.0
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 +4 -4
- data/Gemfile.lock +42 -16
- data/MIGRATION.md +320 -0
- data/README.md +31 -19
- data/a.yml +60 -0
- data/bin/ro +10 -0
- data/lib/ro/_lib.rb +1 -1
- data/lib/ro/asset.rb +48 -6
- data/lib/ro/collection.rb +51 -13
- data/lib/ro/migrator.rb +285 -0
- data/lib/ro/node.rb +53 -13
- data/lib/ro/root.rb +75 -1
- data/lib/ro/script/migrate.rb +204 -0
- data/lib/ro/script/server.rb +1 -1
- data/lib/ro.rb +1 -0
- data/public/api/ro/index-1.json +82 -148
- data/public/api/ro/index.json +82 -148
- data/public/api/ro/nerd/fastest-possible-embeddings/index.json +7 -8
- data/public/api/ro/nerd/ima/index.json +3 -4
- data/public/api/ro/nerd/index/index.json +5 -6
- data/public/api/ro/nerd/index-1.json +15 -18
- data/public/api/ro/nerd/index.json +15 -18
- data/public/api/ro/pages/contact/index.json +4 -5
- data/public/api/ro/pages/cv/index.json +3 -4
- data/public/api/ro/pages/disco/index.json +9 -10
- data/public/api/ro/pages/index/index.json +2 -3
- data/public/api/ro/pages/index-1.json +25 -82
- data/public/api/ro/pages/index.json +25 -82
- data/public/api/ro/pages/jess/index.json +4 -5
- data/public/api/ro/pages/now/index.json +3 -4
- data/public/api/ro/posts/almost-died-in-an-ice-cave/index.json +21 -22
- data/public/api/ro/posts/facebook-and-global-extremism/index.json +8 -9
- data/public/api/ro/posts/index-1.json +42 -48
- data/public/api/ro/posts/index.json +42 -48
- data/public/api/ro/posts/lemmings-considered-harmful/index.json +3 -4
- data/public/api/ro/posts/lost-in-the-desert/index.json +3 -4
- data/public/api/ro/posts/mission/index.json +3 -4
- data/public/api/ro/posts/return-your-laptop/index.json +4 -5
- data/ro.gemspec +247 -18
- data/specs/001-simplify-asset-structure/IMPLEMENTATION_SUMMARY.md +212 -0
- data/specs/001-simplify-asset-structure/checklists/requirements.md +36 -0
- data/specs/001-simplify-asset-structure/contracts/collection_api.md +407 -0
- data/specs/001-simplify-asset-structure/contracts/migrator_api.md +461 -0
- data/specs/001-simplify-asset-structure/contracts/node_api.md +294 -0
- data/specs/001-simplify-asset-structure/data-model.md +381 -0
- data/specs/001-simplify-asset-structure/plan.md +90 -0
- data/specs/001-simplify-asset-structure/quickstart.md +575 -0
- data/specs/001-simplify-asset-structure/research.md +333 -0
- data/specs/001-simplify-asset-structure/spec.md +127 -0
- data/specs/001-simplify-asset-structure/tasks.md +349 -0
- data/test/fixtures/new_structure/mixed/test-json.json +5 -0
- data/test/fixtures/new_structure/mixed/test-yaml.yml +3 -0
- data/test/fixtures/new_structure/posts/metadata-only.yml +7 -0
- data/test/fixtures/new_structure/posts/nested-test/assets/subdirectory/image.png +2 -0
- data/test/fixtures/new_structure/posts/nested-test.yml +7 -0
- data/test/fixtures/new_structure/posts/sample-post/assets/body.md +5 -0
- data/test/fixtures/new_structure/posts/sample-post/assets/image.jpg +2 -0
- data/test/fixtures/new_structure/posts/sample-post.yml +7 -0
- data/test/fixtures/old_structure/posts/assets-only/assets/test.txt +1 -0
- data/test/fixtures/old_structure/posts/sample-post/assets/body.md +5 -0
- data/test/fixtures/old_structure/posts/sample-post/assets/image.jpg +2 -0
- data/test/fixtures/old_structure/posts/sample-post/attributes.yml +2 -0
- data/test/integration/ro_integration_test.rb +165 -0
- data/test/test_helper.rb +149 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/migration_test_1760746513/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/migration_test_1760746513/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/migration_test_1760746513/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760746513.backup.20251018001513/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/migration_test_1760746556/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/migration_test_1760746556/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/migration_test_1760746556/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760746556.backup.20251018001556/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/migration_test_1760755248/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/migration_test_1760755248/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/migration_test_1760755248/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/posts/sample-post/attributes.yml +7 -0
- data/test/tmp/migration_test_1760755248.backup.20251018024048/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/migration_test_1760758803/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/migration_test_1760758803/posts/sample-post/image.jpg +2 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/migration_test_1760758803/posts/sample-post.yml +7 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/posts/sample-post/body.md +5 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/posts/sample-post/image.jpg +2 -0
- data/test/tmp/migration_test_1760758803.backup.20251018034003/posts/sample-post.yml +7 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/migration_test_1760758869/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/migration_test_1760758869/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/migration_test_1760758869/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760758869.backup.20251018034109/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/migration_test_1760758920/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/migration_test_1760758920/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/migration_test_1760758920/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760758920.backup.20251018034200/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/migration_test_1760824728/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/migration_test_1760824728/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/migration_test_1760824728/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/migration_test_1760824728/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760824728.backup.20251018215848/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/migration_test_1760844153/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/migration_test_1760844153/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/migration_test_1760844153/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/migration_test_1760844153/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760844153.backup.20251019032233/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/migration_test_1760940939/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/migration_test_1760940939/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/migration_test_1760940939/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/migration_test_1760940939/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760940939.backup.20251020061539/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/migration_test_1760941048/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/migration_test_1760941048/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/migration_test_1760941048/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/migration_test_1760941048/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/posts/assets-only/assets/test.txt +1 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/posts/sample-post/assets/body.md +5 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/posts/sample-post/assets/image.jpg +2 -0
- data/test/tmp/migration_test_1760941048.backup.20251020061728/posts/sample-post/attributes.yml +2 -0
- data/test/tmp/new_structure_test_1760746452/mixed/test-json.json +5 -0
- data/test/tmp/new_structure_test_1760746452/mixed/test-yaml.yml +3 -0
- data/test/tmp/new_structure_test_1760746452/posts/metadata-only.yml +7 -0
- data/test/tmp/new_structure_test_1760746452/posts/nested-test/subdirectory/image.png +2 -0
- data/test/tmp/new_structure_test_1760746452/posts/nested-test.yml +7 -0
- data/test/tmp/new_structure_test_1760746452/posts/sample-post/body.md +5 -0
- data/test/tmp/new_structure_test_1760746452/posts/sample-post/image.jpg +2 -0
- data/test/tmp/new_structure_test_1760746452/posts/sample-post.yml +7 -0
- data/test/unit/asset_test.rb +90 -0
- data/test/unit/collection_test.rb +127 -0
- data/test/unit/migrator_test.rb +209 -0
- data/test/unit/node_test.rb +138 -0
- metadata +127 -19
- data/public/api/ro/pages/about/index.json +0 -60
- /data/public/ro/nerd/{fastest-possible-embeddings/attributes.yml → fastest-possible-embeddings.yml} +0 -0
- /data/public/ro/nerd/{ima/attributes.yml → ima.yml} +0 -0
- /data/public/ro/nerd/{index/attributes.yml → index.yml} +0 -0
- /data/public/ro/pages/{contact/attributes.yml → contact.yml} +0 -0
- /data/public/ro/pages/{cv/attributes.yml → cv.yml} +0 -0
- /data/public/ro/pages/{disco/attributes.yml → disco.yml} +0 -0
- /data/public/ro/pages/{index/attributes.yml → index.yml} +0 -0
- /data/public/ro/pages/{jess/attributes.yml → jess.yml} +0 -0
- /data/public/ro/pages/{now/attributes.yml → now.yml} +0 -0
- /data/public/ro/posts/{almost-died-in-an-ice-cave/attributes.yml → almost-died-in-an-ice-cave.yml} +0 -0
- /data/public/ro/posts/{facebook-and-global-extremism/attributes.yml → facebook-and-global-extremism.yml} +0 -0
- /data/public/ro/posts/{lemmings-considered-harmful/attributes.yml → lemmings-considered-harmful.yml} +0 -0
- /data/public/ro/posts/{lost-in-the-desert/attributes.yml → lost-in-the-desert.yml} +0 -0
- /data/public/ro/posts/{mission/attributes.yml → mission.yml} +0 -0
- /data/public/ro/posts/{return-your-laptop/attributes.yml → return-your-laptop.yml} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce865a6e0af863e98426c6a5822464695d0baf15ab6ebc1b7e0acdbf88cdc51a
|
|
4
|
+
data.tar.gz: 8e20b5b872b2aef30ae6ff524d287266d8d720ff7ffb63c22513160aab773b72
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b32bd17c787b5969801e7fb72146802aaf8758a0003994eb5363b821508fab65128b4d7dfe614c5df2fee1a5f507cf4c88aaeaa37df4799e11303b87e486600
|
|
7
|
+
data.tar.gz: a6dfe0e278908e892f8c79c15003c9b0ccfe7eadde98efb086b0a8d44f4f59716a81bd76c9bc4dd6af854b5b24ffb34ae75a2801c752e66995e0411a7ca36401
|
data/Gemfile.lock
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ro (4.
|
|
5
|
-
ak47 (~> 0.2)
|
|
6
|
-
|
|
4
|
+
ro (4.4.1)
|
|
5
|
+
ak47 (~> 0.2.5)
|
|
6
|
+
front_matter_parser (~> 1.0)
|
|
7
|
+
image_size (~> 3.4)
|
|
7
8
|
kramdown (~> 2.4, >= 2.4.0)
|
|
8
9
|
kramdown-parser-gfm (~> 1.1, >= 1.1.0)
|
|
9
10
|
map (~> 6.6, >= 6.6.0)
|
|
11
|
+
nokogiri (~> 1)
|
|
12
|
+
rinku (~> 2.0)
|
|
10
13
|
rouge (~> 4.1, >= 4.1.1)
|
|
11
|
-
webrick (~> 1.
|
|
14
|
+
webrick (~> 1.9, >= 1.9.1)
|
|
12
15
|
|
|
13
16
|
GEM
|
|
14
17
|
remote: https://rubygems.org/
|
|
@@ -17,17 +20,18 @@ GEM
|
|
|
17
20
|
guard (~> 0.10.0)
|
|
18
21
|
shell_tools (~> 0.1.0)
|
|
19
22
|
smart_colored
|
|
20
|
-
ffi (1.17.
|
|
21
|
-
ffi (1.17.
|
|
22
|
-
ffi (1.17.
|
|
23
|
-
ffi (1.17.
|
|
24
|
-
ffi (1.17.
|
|
25
|
-
ffi (1.17.
|
|
26
|
-
ffi (1.17.
|
|
27
|
-
ffi (1.17.
|
|
28
|
-
ffi (1.17.
|
|
29
|
-
ffi (1.17.
|
|
30
|
-
ffi (1.17.
|
|
23
|
+
ffi (1.17.2)
|
|
24
|
+
ffi (1.17.2-aarch64-linux-gnu)
|
|
25
|
+
ffi (1.17.2-aarch64-linux-musl)
|
|
26
|
+
ffi (1.17.2-arm-linux-gnu)
|
|
27
|
+
ffi (1.17.2-arm-linux-musl)
|
|
28
|
+
ffi (1.17.2-arm64-darwin)
|
|
29
|
+
ffi (1.17.2-x86-linux-gnu)
|
|
30
|
+
ffi (1.17.2-x86-linux-musl)
|
|
31
|
+
ffi (1.17.2-x86_64-darwin)
|
|
32
|
+
ffi (1.17.2-x86_64-linux-gnu)
|
|
33
|
+
ffi (1.17.2-x86_64-linux-musl)
|
|
34
|
+
front_matter_parser (1.0.1)
|
|
31
35
|
guard (0.10.0)
|
|
32
36
|
ffi (>= 0.5.0)
|
|
33
37
|
thor (~> 0.14.6)
|
|
@@ -37,12 +41,34 @@ GEM
|
|
|
37
41
|
kramdown-parser-gfm (1.1.0)
|
|
38
42
|
kramdown (~> 2.0)
|
|
39
43
|
map (6.6.0)
|
|
44
|
+
mini_portile2 (2.8.8)
|
|
45
|
+
nokogiri (1.18.8)
|
|
46
|
+
mini_portile2 (~> 2.8.2)
|
|
47
|
+
racc (~> 1.4)
|
|
48
|
+
nokogiri (1.18.8-aarch64-linux-gnu)
|
|
49
|
+
racc (~> 1.4)
|
|
50
|
+
nokogiri (1.18.8-aarch64-linux-musl)
|
|
51
|
+
racc (~> 1.4)
|
|
52
|
+
nokogiri (1.18.8-arm-linux-gnu)
|
|
53
|
+
racc (~> 1.4)
|
|
54
|
+
nokogiri (1.18.8-arm-linux-musl)
|
|
55
|
+
racc (~> 1.4)
|
|
56
|
+
nokogiri (1.18.8-arm64-darwin)
|
|
57
|
+
racc (~> 1.4)
|
|
58
|
+
nokogiri (1.18.8-x86_64-darwin)
|
|
59
|
+
racc (~> 1.4)
|
|
60
|
+
nokogiri (1.18.8-x86_64-linux-gnu)
|
|
61
|
+
racc (~> 1.4)
|
|
62
|
+
nokogiri (1.18.8-x86_64-linux-musl)
|
|
63
|
+
racc (~> 1.4)
|
|
64
|
+
racc (1.8.1)
|
|
40
65
|
rexml (3.3.9)
|
|
66
|
+
rinku (2.0.6)
|
|
41
67
|
rouge (4.4.0)
|
|
42
68
|
shell_tools (0.1.2)
|
|
43
69
|
smart_colored (1.1.1)
|
|
44
70
|
thor (0.14.6)
|
|
45
|
-
webrick (1.
|
|
71
|
+
webrick (1.9.1)
|
|
46
72
|
|
|
47
73
|
PLATFORMS
|
|
48
74
|
aarch64-linux-gnu
|
data/MIGRATION.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Ro v5.0 Asset Structure Migration Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Ro v5.0 introduces a simplified asset directory structure that reduces nesting depth and makes assets easier to understand and manage.
|
|
6
|
+
|
|
7
|
+
### Automatic Warning System
|
|
8
|
+
|
|
9
|
+
Ro v5.0 automatically detects when you're using old structure data and warns you on stderr:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
⚠️ WARNING: Old Ro asset structure detected!
|
|
13
|
+
|
|
14
|
+
This Ro root contains assets in the OLD structure format:
|
|
15
|
+
• identifier/attributes.yml
|
|
16
|
+
• identifier/assets/
|
|
17
|
+
|
|
18
|
+
Ro v5.0 uses a simplified NEW structure:
|
|
19
|
+
• identifier.yml
|
|
20
|
+
• identifier/
|
|
21
|
+
|
|
22
|
+
Collections will NOT automatically discover old-structure nodes.
|
|
23
|
+
|
|
24
|
+
To migrate your data, run:
|
|
25
|
+
ro migrate /path/to/your/data
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**This warning does NOT stop your program** - it's informational to help you know you need to migrate. The warning appears once per root directory when `Ro::Root.new` is called.
|
|
29
|
+
|
|
30
|
+
### Old Structure (v4.x)
|
|
31
|
+
```
|
|
32
|
+
posts/
|
|
33
|
+
sample-post/
|
|
34
|
+
attributes.yml # Metadata file INSIDE node directory
|
|
35
|
+
assets/ # Assets subdirectory
|
|
36
|
+
image.jpg
|
|
37
|
+
document.pdf
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### New Structure (v5.0)
|
|
41
|
+
```
|
|
42
|
+
posts/
|
|
43
|
+
sample-post.yml # Metadata file at COLLECTION level (moved out)
|
|
44
|
+
sample-post/ # Node directory (same location)
|
|
45
|
+
assets/ # Assets subdirectory (SAME location as before!)
|
|
46
|
+
image.jpg
|
|
47
|
+
document.pdf
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Benefits
|
|
51
|
+
|
|
52
|
+
- **Simpler**: One less level of nesting
|
|
53
|
+
- **Clearer**: Metadata file and assets directory are siblings, not parent/child
|
|
54
|
+
- **Faster**: Easier to locate assets by identifier
|
|
55
|
+
- **More Intuitive**: Structure is self-documenting
|
|
56
|
+
|
|
57
|
+
## Migration Tool
|
|
58
|
+
|
|
59
|
+
Ro v5.0 includes a migration tool to automate the conversion from old to new structure.
|
|
60
|
+
|
|
61
|
+
### Basic Usage
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Preview migration (dry run)
|
|
65
|
+
./bin/ro migrate --dry-run /path/to/your/ro/root
|
|
66
|
+
|
|
67
|
+
# Run migration with backup (recommended)
|
|
68
|
+
./bin/ro migrate /path/to/your/ro/root
|
|
69
|
+
|
|
70
|
+
# Run migration without backup (not recommended)
|
|
71
|
+
./bin/ro migrate --no-backup /path/to/your/ro/root
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Options
|
|
75
|
+
|
|
76
|
+
- `--dry-run`, `-d`: Preview changes without making them
|
|
77
|
+
- `--backup`, `--no-backup`, `-b`: Create backup before migrating (default: true)
|
|
78
|
+
- `--verbose`, `-v`: Show detailed progress
|
|
79
|
+
- `--force`, `-f`: Force migration even if new structure detected
|
|
80
|
+
- `--help`, `-h`: Show help message
|
|
81
|
+
|
|
82
|
+
### Migration Process
|
|
83
|
+
|
|
84
|
+
The migration tool:
|
|
85
|
+
|
|
86
|
+
1. **Validates** the structure to detect old/new/mixed formats
|
|
87
|
+
2. **Creates a backup** (unless `--no-backup` is specified)
|
|
88
|
+
3. **For each old-structure node directory**:
|
|
89
|
+
- **If node has attributes file**: Moves `identifier/attributes.yml` → `identifier.yml` (at collection level)
|
|
90
|
+
- **If node has NO attributes**: Creates empty `identifier.yml` with `{}` content
|
|
91
|
+
- Assets remain in `identifier/assets/` (no change needed!)
|
|
92
|
+
|
|
93
|
+
**Important**: The migrator processes ALL node directories, even those without an attributes file. This ensures every node is discoverable in the new structure.
|
|
94
|
+
|
|
95
|
+
### Safety Features
|
|
96
|
+
|
|
97
|
+
- **Automatic backups**: Creates timestamped backup before migration
|
|
98
|
+
- **Dry run mode**: Preview changes before applying
|
|
99
|
+
- **Validation**: Detects mixed structures and warns
|
|
100
|
+
- **Rollback support**: Can restore from backup if needed
|
|
101
|
+
|
|
102
|
+
## Manual Migration
|
|
103
|
+
|
|
104
|
+
If you prefer to migrate manually:
|
|
105
|
+
|
|
106
|
+
1. **For each node WITH attributes**:
|
|
107
|
+
```bash
|
|
108
|
+
cd posts
|
|
109
|
+
|
|
110
|
+
# Move metadata file out to collection level
|
|
111
|
+
mv sample-post/attributes.yml sample-post.yml
|
|
112
|
+
|
|
113
|
+
# Assets stay in sample-post/assets/
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
2. **For each node WITHOUT attributes** (assets-only):
|
|
117
|
+
```bash
|
|
118
|
+
cd posts
|
|
119
|
+
|
|
120
|
+
# Create empty metadata file at collection level
|
|
121
|
+
echo '{}' > orphan-assets.yml
|
|
122
|
+
|
|
123
|
+
# Assets stay in orphan-assets/assets/
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
3. **Update your code** to use Ro v5.0
|
|
127
|
+
|
|
128
|
+
## Rollback
|
|
129
|
+
|
|
130
|
+
If you need to rollback after migration:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
# Using the Migrator class
|
|
134
|
+
migrator = Ro::Migrator.new('/path/to/ro/root')
|
|
135
|
+
migrator.rollback
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This will restore from the most recent backup.
|
|
139
|
+
|
|
140
|
+
## Migration Checklist
|
|
141
|
+
|
|
142
|
+
- [ ] Review migration plan with `--dry-run`
|
|
143
|
+
- [ ] Backup your data (migration creates backup automatically)
|
|
144
|
+
- [ ] Run migration: `./bin/ro migrate /path/to/ro/root`
|
|
145
|
+
- [ ] Verify migrated data loads correctly
|
|
146
|
+
- [ ] Test your application with new structure
|
|
147
|
+
- [ ] Update code to Ro v5.0 if needed
|
|
148
|
+
- [ ] Remove old backups once confident
|
|
149
|
+
|
|
150
|
+
## Breaking Changes
|
|
151
|
+
|
|
152
|
+
### API Changes
|
|
153
|
+
|
|
154
|
+
**Node initialization**:
|
|
155
|
+
```ruby
|
|
156
|
+
# Old (v4.x) - still works for backward compatibility
|
|
157
|
+
node = Ro::Node.new(node_directory_path)
|
|
158
|
+
|
|
159
|
+
# New (v5.0) - preferred for new structure
|
|
160
|
+
node = Ro::Node.new(collection, metadata_file)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Asset paths**:
|
|
164
|
+
```ruby
|
|
165
|
+
# Both old and new structure
|
|
166
|
+
node.asset_dir # => identifier/assets/
|
|
167
|
+
|
|
168
|
+
# The assets/ subdirectory stays the same!
|
|
169
|
+
# Only the metadata file location changes
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### What Stays the Same
|
|
173
|
+
|
|
174
|
+
- **Metadata format**: YAML/JSON/TOML structure unchanged
|
|
175
|
+
- **Asset access**: `node.assets`, `node.asset_paths` work the same
|
|
176
|
+
- **Collection access**: `root['collection']['node']` unchanged
|
|
177
|
+
- **Attribute access**: `node[:title]`, `node.attributes` unchanged
|
|
178
|
+
|
|
179
|
+
## Testing
|
|
180
|
+
|
|
181
|
+
Run tests to verify migration:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Unit tests
|
|
185
|
+
ruby test/unit/collection_test.rb
|
|
186
|
+
ruby test/unit/node_test.rb
|
|
187
|
+
ruby test/unit/asset_test.rb
|
|
188
|
+
ruby test/unit/migrator_test.rb
|
|
189
|
+
|
|
190
|
+
# Integration tests
|
|
191
|
+
ruby test/integration/ro_integration_test.rb
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Troubleshooting
|
|
195
|
+
|
|
196
|
+
### "Both old and new structures detected"
|
|
197
|
+
|
|
198
|
+
This indicates a partial migration. Options:
|
|
199
|
+
1. Use `--force` to continue migration
|
|
200
|
+
2. Manually inspect and resolve conflicts
|
|
201
|
+
3. Restore from backup and retry
|
|
202
|
+
|
|
203
|
+
### "Node directory not found"
|
|
204
|
+
|
|
205
|
+
Ensure you're running the migration from the correct root directory.
|
|
206
|
+
|
|
207
|
+
### Assets not loading after migration
|
|
208
|
+
|
|
209
|
+
Check that:
|
|
210
|
+
1. Metadata files are at collection level (e.g., `posts/sample-post.yml`)
|
|
211
|
+
2. Node directories exist at collection level (e.g., `posts/sample-post/`)
|
|
212
|
+
3. Assets are in the `assets/` subdirectory (e.g., `posts/sample-post/assets/image.jpg`)
|
|
213
|
+
|
|
214
|
+
## Examples
|
|
215
|
+
|
|
216
|
+
### Example 1: Single Collection
|
|
217
|
+
|
|
218
|
+
Before:
|
|
219
|
+
```
|
|
220
|
+
ro_data/
|
|
221
|
+
posts/
|
|
222
|
+
welcome/
|
|
223
|
+
attributes.yml
|
|
224
|
+
assets/
|
|
225
|
+
banner.jpg
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
After:
|
|
229
|
+
```
|
|
230
|
+
ro_data/
|
|
231
|
+
posts/
|
|
232
|
+
welcome.yml ← Metadata moved out
|
|
233
|
+
welcome/
|
|
234
|
+
assets/
|
|
235
|
+
banner.jpg ← Assets stay in same location
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Example 2: Multiple Collections
|
|
239
|
+
|
|
240
|
+
Before:
|
|
241
|
+
```
|
|
242
|
+
ro_data/
|
|
243
|
+
posts/
|
|
244
|
+
post-1/
|
|
245
|
+
attributes.yml
|
|
246
|
+
assets/
|
|
247
|
+
image.jpg
|
|
248
|
+
pages/
|
|
249
|
+
about/
|
|
250
|
+
attributes.yml
|
|
251
|
+
assets/
|
|
252
|
+
photo.png
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
After:
|
|
256
|
+
```
|
|
257
|
+
ro_data/
|
|
258
|
+
posts/
|
|
259
|
+
post-1.yml
|
|
260
|
+
post-1/
|
|
261
|
+
assets/
|
|
262
|
+
image.jpg
|
|
263
|
+
pages/
|
|
264
|
+
about.yml
|
|
265
|
+
about/
|
|
266
|
+
assets/
|
|
267
|
+
photo.png
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Example 3: Metadata-Only Node
|
|
271
|
+
|
|
272
|
+
Before:
|
|
273
|
+
```
|
|
274
|
+
ro_data/
|
|
275
|
+
posts/
|
|
276
|
+
text-only/
|
|
277
|
+
attributes.yml
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
After:
|
|
281
|
+
```
|
|
282
|
+
ro_data/
|
|
283
|
+
posts/
|
|
284
|
+
text-only.yml
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Example 4: Assets-Only Node (No Attributes)
|
|
288
|
+
|
|
289
|
+
Before:
|
|
290
|
+
```
|
|
291
|
+
ro_data/
|
|
292
|
+
posts/
|
|
293
|
+
orphan-assets/ ← Directory with no attributes.yml
|
|
294
|
+
assets/
|
|
295
|
+
image.jpg
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
After:
|
|
299
|
+
```
|
|
300
|
+
ro_data/
|
|
301
|
+
posts/
|
|
302
|
+
orphan-assets.yml ← Empty metadata file created: {}
|
|
303
|
+
orphan-assets/
|
|
304
|
+
assets/
|
|
305
|
+
image.jpg
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Support
|
|
309
|
+
|
|
310
|
+
For issues or questions:
|
|
311
|
+
- GitHub Issues: https://github.com/ahoward/ro/issues
|
|
312
|
+
- Documentation: See README.md and code comments
|
|
313
|
+
|
|
314
|
+
## Version Compatibility
|
|
315
|
+
|
|
316
|
+
- **Ro v4.x**: Old structure only
|
|
317
|
+
- **Ro v5.0**: Both structures (with backward compatibility)
|
|
318
|
+
- **Ro v6.0+**: New structure only (planned)
|
|
319
|
+
|
|
320
|
+
**Recommendation**: Migrate to new structure before Ro v6.0 release.
|
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@ it is one part cms, one part database, one part api, and one part magic.
|
|
|
9
9
|
|
|
10
10
|
if you used a headless cms, it's like that, before they existed, except way better, and free.
|
|
11
11
|
|
|
12
|
-
with `ro`, you can
|
|
12
|
+
with `ro`, you can separate your content from presentation, like a sane and decent human being.
|
|
13
13
|
|
|
14
14
|
> silent code whispers
|
|
15
15
|
> github's gentle, peaceful hush
|
|
@@ -36,16 +36,17 @@ for a real site.
|
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
38
|
|
|
39
|
-
drawohara@drawohara.dev:ro[main] #=> tree public/ro/posts/
|
|
40
|
-
public/ro/posts/
|
|
41
|
-
├──
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
drawohara@drawohara.dev:ro[main] #=> tree public/ro/posts/
|
|
40
|
+
public/ro/posts/
|
|
41
|
+
├── almost-died-in-an-ice-cave.yml # ← metadata file at collection level
|
|
42
|
+
└── almost-died-in-an-ice-cave/ # ← node directory
|
|
43
|
+
├── assets/ # ← assets subdirectory
|
|
44
|
+
│ ├── image1.png
|
|
45
|
+
│ ├── image2.png
|
|
46
|
+
│ ├── image3.png
|
|
47
|
+
│ ├── og.jpg
|
|
48
|
+
│ └── purple-heart.jpg
|
|
49
|
+
└── body.md # ← other content files
|
|
49
50
|
|
|
50
51
|
```
|
|
51
52
|
|
|
@@ -53,15 +54,22 @@ in this example you can see a few things, regarding the layout of a `ro` directo
|
|
|
53
54
|
|
|
54
55
|
- `ro` content often, but is not required, to live in `public`. more on this below.
|
|
55
56
|
|
|
56
|
-
- the essential layout is
|
|
57
|
+
- the essential layout is (v5.0+):
|
|
57
58
|
|
|
58
59
|
```ruby
|
|
59
60
|
|
|
60
61
|
@root = "ro"
|
|
61
62
|
@collection = "posts"
|
|
62
|
-
@id
|
|
63
|
+
@id = "almost-died-in-an-ice-cave"
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
# metadata file
|
|
66
|
+
"#{ @root }/#{ @collection }/#{ @id }.yml"
|
|
67
|
+
|
|
68
|
+
# node directory
|
|
69
|
+
"#{ @root }/#{ @collection }/#{ @id }/"
|
|
70
|
+
|
|
71
|
+
# assets
|
|
72
|
+
"#{ @root }/#{ @collection }/#{ @id }/assets/"
|
|
65
73
|
|
|
66
74
|
```
|
|
67
75
|
|
|
@@ -85,7 +93,7 @@ if you learn best by example, you can examine the `ro` directory of my own websi
|
|
|
85
93
|
|
|
86
94
|
more about this can be rtfm'd here -> https://github.com/ahoward/ro/blob/main/lib/ro.rb#L29-L55
|
|
87
95
|
|
|
88
|
-
because not having a repl sucks,
|
|
96
|
+
because not having a repl sucks, `ro` has one. you should too.
|
|
89
97
|
|
|
90
98
|
```sh
|
|
91
99
|
|
|
@@ -158,7 +166,7 @@ you will end up with html that looks like so:
|
|
|
158
166
|
|
|
159
167
|
<a href='/ro/posts/foo-bar/assets/report.pdf'>linky</a>
|
|
160
168
|
|
|
161
|
-
<img src='/ro/posts/foo-bar/assets/pretty.png'
|
|
169
|
+
<img src='/ro/posts/foo-bar/assets/pretty.png' alt='alty'>
|
|
162
170
|
|
|
163
171
|
|
|
164
172
|
```
|
|
@@ -195,13 +203,13 @@ attributes will be expanded too, at any depth. eg. -> https://github.com/ahowar
|
|
|
195
203
|
this means code like this:
|
|
196
204
|
|
|
197
205
|
```yaml
|
|
198
|
-
# file: public/ro/posts/foo-bar
|
|
206
|
+
# file: public/ro/posts/foo-bar.yml
|
|
199
207
|
|
|
200
208
|
og:
|
|
201
209
|
image: ./assets/og.jpg
|
|
202
210
|
```
|
|
203
211
|
|
|
204
|
-
will 'just work'. of course, this assumes that 'public/ro/foo-bar/assets/og.jpg' exists!
|
|
212
|
+
will 'just work'. of course, this assumes that 'public/ro/posts/foo-bar/assets/og.jpg' exists!
|
|
205
213
|
|
|
206
214
|
the code is rather robust here, and is not a simple string bashing approach.
|
|
207
215
|
|
|
@@ -266,7 +274,7 @@ lil detail about that link^, it is from *10 years ago*, when dojo4 was still run
|
|
|
266
274
|
|
|
267
275
|
---
|
|
268
276
|
|
|
269
|
-
one super
|
|
277
|
+
one super common pattern, is to add a build step to a github workflow, and
|
|
270
278
|
then publish the js api via gh-pages. see an example here:
|
|
271
279
|
|
|
272
280
|
https://github.com/ahoward/ro/blob/main/.github/workflows/gh-pages.yml
|
|
@@ -339,3 +347,7 @@ https://github.com/LGUG2Z/komorebi-license
|
|
|
339
347
|
AI
|
|
340
348
|
--
|
|
341
349
|
suck it 🤖s!
|
|
350
|
+
|
|
351
|
+
REF
|
|
352
|
+
---
|
|
353
|
+
https://github.com/ahoward/ro
|
data/a.yml
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Simple workflow for deploying static content to GitHub Pages
|
|
2
|
+
name: deploy ro content, api, and site to gh-pages
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
# Runs on pushes targeting the default branch
|
|
6
|
+
push:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
|
|
9
|
+
# Allows you to run this workflow manually from the Actions tab
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pages: write
|
|
16
|
+
id-token: write
|
|
17
|
+
|
|
18
|
+
# allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
|
19
|
+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
|
20
|
+
concurrency:
|
|
21
|
+
group: "pages"
|
|
22
|
+
cancel-in-progress: false
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
# single deploy job since we're just deploying
|
|
26
|
+
deploy:
|
|
27
|
+
environment:
|
|
28
|
+
name: github-pages
|
|
29
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: checkout
|
|
33
|
+
# NOTE: this enables git-lfs and caching
|
|
34
|
+
# - https://github.com/actions/checkout/issues/834
|
|
35
|
+
# - https://github.com/nschloe/action-cached-lfs-checkout
|
|
36
|
+
uses: nschloe/action-cached-lfs-checkout@v1
|
|
37
|
+
# you may use this instead, if you don't want git-lfs caching
|
|
38
|
+
#uses: actions/checkout@v4
|
|
39
|
+
#with:
|
|
40
|
+
# lfs: true
|
|
41
|
+
- name: setup gh-pages
|
|
42
|
+
uses: actions/configure-pages@v3
|
|
43
|
+
id: gh-pages
|
|
44
|
+
- name: ro build
|
|
45
|
+
uses: ruby/setup-ruby@v1
|
|
46
|
+
with:
|
|
47
|
+
bundler-cache: true
|
|
48
|
+
- run: |
|
|
49
|
+
export RO_URL=${{ steps.gh-pages.outputs.base_url }}/ro
|
|
50
|
+
export RO_PAGE_SIZE=2
|
|
51
|
+
bundle exec ./bin/ro build ./public/ro ./public/api/ro
|
|
52
|
+
bundle exec ro site public
|
|
53
|
+
tree ./public
|
|
54
|
+
- name: upload artifact
|
|
55
|
+
uses: actions/upload-pages-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
path: "./public"
|
|
58
|
+
- name: deploy gh-pages
|
|
59
|
+
id: deployment
|
|
60
|
+
uses: actions/deploy-pages@v2
|
data/bin/ro
CHANGED
|
@@ -130,6 +130,10 @@ Ro.script do
|
|
|
130
130
|
site!
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
+
run(:migrate) do
|
|
134
|
+
migrate!
|
|
135
|
+
end
|
|
136
|
+
|
|
133
137
|
def setup!(*which)
|
|
134
138
|
setup_env!
|
|
135
139
|
|
|
@@ -259,6 +263,12 @@ Ro.script do
|
|
|
259
263
|
index_html.binwrite(html)
|
|
260
264
|
puts index_html
|
|
261
265
|
end
|
|
266
|
+
|
|
267
|
+
def migrate!
|
|
268
|
+
require "#{$libdir}/ro/script/migrate.rb"
|
|
269
|
+
|
|
270
|
+
Ro::Script::Migrate.run!(script: self)
|
|
271
|
+
end
|
|
262
272
|
end
|
|
263
273
|
|
|
264
274
|
BEGIN {
|
data/lib/ro/_lib.rb
CHANGED
data/lib/ro/asset.rb
CHANGED
|
@@ -9,13 +9,53 @@ module Ro
|
|
|
9
9
|
|
|
10
10
|
@path = Path.for(arg, *args)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
# T029: Updated to split on node ID instead of /assets/ segment
|
|
13
|
+
@node = options.fetch(:node) do
|
|
14
|
+
# Try to find node by splitting path
|
|
15
|
+
# In new structure: no /assets/ segment
|
|
16
|
+
# In old structure: /assets/ segment exists
|
|
17
|
+
if @path.to_s.include?('/assets/')
|
|
18
|
+
# Old structure
|
|
19
|
+
Node.for(@path.split('/assets/').first)
|
|
20
|
+
else
|
|
21
|
+
# New structure: find node directory by looking at parent paths
|
|
22
|
+
# Asset path like: /collection/node-id/file.jpg
|
|
23
|
+
# Node path should be: /collection/node-id
|
|
24
|
+
found_node = nil
|
|
25
|
+
node_path = @path.parent
|
|
26
|
+
while node_path && !node_path.basename.to_s.match(/\.(yml|yaml|json|toml)$/)
|
|
27
|
+
# Check if there's a metadata file for this directory
|
|
28
|
+
collection_path = node_path.parent
|
|
29
|
+
node_id = node_path.basename.to_s
|
|
30
|
+
|
|
31
|
+
%w[yml yaml json toml].each do |ext|
|
|
32
|
+
metadata_file = collection_path.join("#{node_id}.#{ext}")
|
|
33
|
+
if metadata_file.exist?
|
|
34
|
+
root = Root.for(collection_path.parent)
|
|
35
|
+
collection = root.collection_for(collection_path)
|
|
36
|
+
found_node = Node.new(collection, metadata_file)
|
|
37
|
+
break
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
break if found_node
|
|
42
|
+
node_path = node_path.parent
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Fallback: old behavior
|
|
46
|
+
found_node || Node.for(@path.split('/assets/').first)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# T030: Updated relative_path calculation for new structure
|
|
51
|
+
# In new structure, path is already relative to node.asset_dir
|
|
52
|
+
# In old structure, need to account for assets/ prefix
|
|
53
|
+
@relative_path = @path.relative_to(@node.asset_dir)
|
|
15
54
|
|
|
16
55
|
@name = @relative_path
|
|
17
56
|
|
|
18
|
-
|
|
57
|
+
# URL needs to include 'assets/' prefix since assets live in assets/ subdirectory
|
|
58
|
+
@url = @node.url_for(Path.relative('assets', @relative_path))
|
|
19
59
|
|
|
20
60
|
super(@path)
|
|
21
61
|
end
|
|
@@ -33,8 +73,10 @@ module Ro
|
|
|
33
73
|
|
|
34
74
|
def is_src?
|
|
35
75
|
key = relative_path.parts
|
|
36
|
-
|
|
37
|
-
|
|
76
|
+
# Check if the first directory in the path is 'src'
|
|
77
|
+
# e.g., src/file.js or src/subdir/file.js
|
|
78
|
+
first_dir = key.size >= 2 ? key[0] : nil
|
|
79
|
+
!!(first_dir == 'src')
|
|
38
80
|
end
|
|
39
81
|
|
|
40
82
|
alias is_src is_src?
|