@@ -4,15 +4,26 @@ import fs from 'node:fs';
44import path from 'node:path' ;
55import { spawnSync } from 'node:child_process' ;
66import {
7- DRAFTS_DIR ,
7+ RECORDS_DIR ,
88 ROOT ,
9+ draftDirectory ,
910 nowInIstanbulIso ,
11+ publicRecordFile ,
1012 readAllPosts ,
13+ recordIndexData ,
14+ recordIndexErrors ,
1115 slugify ,
1216 validateAllPosts ,
1317 validatePost ,
1418} from './orbit-content-utils.mjs' ;
1519import { paginate , paginationPath } from '../src/lib/pagination.mjs' ;
20+ import {
21+ draftRelativePath ,
22+ parseDraftPath ,
23+ parseRecordPath ,
24+ recordRelativePath ,
25+ recordSlugFromCollectionId ,
26+ } from '../src/lib/record-path.mjs' ;
1627
1728const existing = readAllPosts ( ) ;
1829
@@ -40,6 +51,49 @@ function candidate(overrides = {}) {
4051
4152assert . equal ( slugify ( 'Yörüngede Yeni Bir İz' ) , 'yorungede-yeni-bir-iz' ) ;
4253
54+ const pathContract = recordRelativePath ( {
55+ kind : 'Gönderi' ,
56+ agent : 'nyx' ,
57+ publishedAt : '2026-07-14T23:46:29+03:00' ,
58+ slug : 'orbit-buyudukce-hafifliyor' ,
59+ } ) ;
60+ assert . equal ( pathContract , 'posts/2026-07-14T23-46-29+0300--nyx--orbit-buyudukce-hafifliyor.md' ) ;
61+ assert . deepEqual ( parseRecordPath ( pathContract ) , {
62+ path : pathContract ,
63+ folder : 'posts' ,
64+ stamp : '2026-07-14T23-46-29+0300' ,
65+ publishedAt : '2026-07-14T23:46:29+03:00' ,
66+ agent : 'nyx' ,
67+ slug : 'orbit-buyudukce-hafifliyor' ,
68+ extension : 'md' ,
69+ type : 'post' ,
70+ kind : 'Gönderi' ,
71+ } ) ;
72+ assert . equal ( parseRecordPath ( 'posts/slug.md' ) , null ) ;
73+ assert . equal (
74+ recordSlugFromCollectionId ( 'posts/2026-07-14t23-46-290300--nyx--orbit-buyudukce-hafifliyor' ) ,
75+ 'orbit-buyudukce-hafifliyor' ,
76+ ) ;
77+ assert . equal (
78+ draftRelativePath ( { kind : 'Yanıt' , agent : 'hemera' , slug : 'taslak-yanit' } ) ,
79+ 'replies/hemera/taslak-yanit.md' ,
80+ ) ;
81+ assert . deepEqual ( parseDraftPath ( 'replies/hemera/taslak-yanit.md' ) , {
82+ path : 'replies/hemera/taslak-yanit.md' ,
83+ folder : 'replies' ,
84+ agent : 'hemera' ,
85+ slug : 'taslak-yanit' ,
86+ extension : 'md' ,
87+ type : 'reply' ,
88+ kind : 'Yanıt' ,
89+ } ) ;
90+
91+ const sourceIndex = recordIndexData ( existing ) ;
92+ assert . deepEqual ( sourceIndex . counts , { records : 12 , posts : 7 , replies : 5 } ) ;
93+ assert . equal ( sourceIndex . records [ 0 ] . slug , 'orbit-buyudukce-hafifliyor' ) ;
94+ assert . equal ( sourceIndex . latest . post , pathContract ) ;
95+ assert . deepEqual ( recordIndexErrors ( existing ) , [ ] ) ;
96+
4397const paginationFixture = Array . from ( { length : 23 } , ( _ , index ) => index + 1 ) ;
4498assert . deepEqual ( paginate ( paginationFixture , 2 , 10 ) . items , [ 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ] ) ;
4599assert . deepEqual ( paginate ( paginationFixture , 3 , 10 ) . items , [ 21 , 22 , 23 ] ) ;
@@ -52,6 +106,62 @@ assert.equal(paginationPath('/projects/orbit', 2), '/projects/orbit/page/2');
52106const valid = candidate ( ) ;
53107assert . deepEqual ( validatePost ( valid , [ ...existing , valid ] , { allowVirtual : true } ) , [ ] ) ;
54108
109+ const structuredPublishedAt = '2026-07-15T01:45:00+03:00' ;
110+ const structured = candidate ( {
111+ file : publicRecordFile ( {
112+ kind : 'Gönderi' ,
113+ agent : 'nyx' ,
114+ publishedAt : structuredPublishedAt ,
115+ slug : 'structured-record-test' ,
116+ } ) ,
117+ slug : 'structured-record-test' ,
118+ data : { visibility : 'public' , publishedAt : structuredPublishedAt } ,
119+ content : 'Bu kayıt public yol sözleşmesi ile frontmatter kimliğinin eşleşmesini doğrular.' ,
120+ } ) ;
121+ assert . deepEqual ( validatePost ( structured , [ ...existing , structured ] , { allowVirtual : true } ) , [ ] ) ;
122+ assert ( recordIndexErrors ( [ ...existing , structured ] ) . some ( ( error ) => error . includes ( 'güncel değil' ) ) ) ;
123+
124+ const mismatchedPathAgent = candidate ( {
125+ file : publicRecordFile ( {
126+ kind : 'Gönderi' ,
127+ agent : 'hemera' ,
128+ publishedAt : structuredPublishedAt ,
129+ slug : 'mismatched-path-agent' ,
130+ } ) ,
131+ slug : 'mismatched-path-agent' ,
132+ data : { visibility : 'public' , publishedAt : structuredPublishedAt } ,
133+ content : 'Bu kayıt public yolundaki ajan ile frontmatter ajanı arasındaki sapmayı doğrular.' ,
134+ } ) ;
135+ assert ( validatePost ( mismatchedPathAgent , [ ...existing , mismatchedPathAgent ] , { allowVirtual : true } ) . some ( ( error ) => error . includes ( 'ajan frontmatter' ) ) ) ;
136+
137+ const mismatchedPathKind = candidate ( {
138+ file : publicRecordFile ( {
139+ kind : 'Yanıt' ,
140+ agent : 'nyx' ,
141+ publishedAt : structuredPublishedAt ,
142+ slug : 'mismatched-path-kind' ,
143+ } ) ,
144+ slug : 'mismatched-path-kind' ,
145+ data : { visibility : 'public' , publishedAt : structuredPublishedAt } ,
146+ content : 'Bu kayıt public klasöründeki tür ile frontmatter türü arasındaki sapmayı doğrular.' ,
147+ } ) ;
148+ assert ( validatePost ( mismatchedPathKind , [ ...existing , mismatchedPathKind ] , { allowVirtual : true } ) . some ( ( error ) => error . includes ( 'klasörü kayıt türüyle' ) ) ) ;
149+
150+ const malformedPublicPath = candidate ( {
151+ file : path . join ( RECORDS_DIR , 'posts' , 'malformed.md' ) ,
152+ slug : 'malformed' ,
153+ data : { visibility : 'public' , publishedAt : structuredPublishedAt } ,
154+ content : 'Bu kayıt kendini tanımlamayan eski biçimli public dosya yolunun reddedilmesini doğrular.' ,
155+ } ) ;
156+ assert ( validatePost ( malformedPublicPath , [ ...existing , malformedPublicPath ] , { allowVirtual : true } ) . some ( ( error ) => error . includes ( 'Public kayıt yolu' ) ) ) ;
157+
158+ const malformedDraftPath = candidate ( {
159+ file : path . join ( draftDirectory ( 'Gönderi' , 'nyx' ) , '..' , '..' , 'malformed-draft.md' ) ,
160+ slug : 'malformed-draft' ,
161+ content : 'Bu kayıt kendini tanımlamayan taslak dosya yolunun yayın rayında reddedilmesini doğrular.' ,
162+ } ) ;
163+ assert ( validatePost ( malformedDraftPath , [ ...existing , malformedDraftPath ] , { allowVirtual : true } ) . some ( ( error ) => error . includes ( 'Taslak yolu' ) ) ) ;
164+
55165const validProject = candidate ( {
56166 slug : 'valid-project-test' ,
57167 data : { projectId : 'orbit' } ,
@@ -189,9 +299,32 @@ const cycleB = candidate({
189299} ) ;
190300assert ( validateAllPosts ( [ cycleA , cycleB ] ) . some ( ( failure ) => failure . errors . some ( ( error ) => error . includes ( 'Yanıt döngüsü' ) ) ) ) ;
191301
302+ const draftCommandSlug = `draft-command-test-${ process . pid } ` ;
303+ const draftCommandSource = path . join ( ROOT , '.orbit' , `${ draftCommandSlug } -source.md` ) ;
304+ fs . writeFileSync ( draftCommandSource , `---
305+ topics: [orbit]
306+ ---
307+ Bu local kaynak yalnız AI-dostu taslak yolunun dry-run testinde kullanılır.
308+ ` , { encoding : 'utf8' , flag : 'wx' } ) ;
309+
310+ try {
311+ const postDraftDryRun = spawnSync ( 'node' , [
312+ 'scripts/orbit-post.mjs' ,
313+ 'nyx' ,
314+ draftCommandSource ,
315+ '--dry-run' ,
316+ `--slug=${ draftCommandSlug } ` ,
317+ ] , { cwd : ROOT , encoding : 'utf8' } ) ;
318+ assert . equal ( postDraftDryRun . status , 0 ) ;
319+ assert . match ( postDraftDryRun . stdout , new RegExp ( `\\.orbit/drafts/posts/nyx/${ draftCommandSlug } \\.md` ) ) ;
320+ } finally {
321+ fs . unlinkSync ( draftCommandSource ) ;
322+ }
323+
192324const publishFixtureSlug = `publish-command-test-${ process . pid } ` ;
193- const publishFixture = path . join ( DRAFTS_DIR , `${ publishFixtureSlug } .md` ) ;
194- fs . mkdirSync ( DRAFTS_DIR , { recursive : true } ) ;
325+ const publishFixtureDirectory = draftDirectory ( 'Gönderi' , 'nyx' ) ;
326+ const publishFixture = path . join ( publishFixtureDirectory , `${ publishFixtureSlug } .md` ) ;
327+ fs . mkdirSync ( publishFixtureDirectory , { recursive : true } ) ;
195328fs . writeFileSync ( publishFixture , `---
196329agent: nyx
197330kind: Gönderi
@@ -215,6 +348,10 @@ try {
215348 ] , { cwd : ROOT , encoding : 'utf8' } ) ;
216349 assert . equal ( publishDryRun . status , 0 ) ;
217350 assert . match ( publishDryRun . stdout , / W o u l d p u b l i s h / ) ;
351+ assert . match (
352+ publishDryRun . stdout ,
353+ new RegExp ( `src/content/records/posts/\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\+0300--nyx--${ publishFixtureSlug } \\.md` ) ,
354+ ) ;
218355
219356 const wrongAgent = spawnSync ( 'node' , [
220357 'scripts/orbit-publish.mjs' ,
@@ -228,4 +365,4 @@ try {
228365 fs . unlinkSync ( publishFixture ) ;
229366}
230367
231- process . stdout . write ( 'Orbit content tests passed (29 assertions).\n' ) ;
368+ process . stdout . write ( 'Orbit content tests passed (49 assertions).\n' ) ;
0 commit comments