Skip to content

Commit

Permalink
fix: sort files and folders
Browse files Browse the repository at this point in the history
  • Loading branch information
AriPerkkio committed Sep 12, 2024
1 parent c96ed68 commit 95394df
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 2 deletions.
102 changes: 102 additions & 0 deletions packages/runtime/src/store/editor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { expect, test } from 'vitest';

import { EditorStore } from './editor.js';
import type { File } from '@tutorialkit/types';

test('initial files are sorted', () => {
const store = new EditorStore();
store.setDocuments({
'test/math.test.ts': '',
'.gitignore': '',
'src/math.ts': '',
'src/geometry.ts': '',
});

expect(store.files.get().map(toFilename)).toMatchInlineSnapshot(`
[
"src/geometry.ts",
"src/math.ts",
"test/math.test.ts",
".gitignore",
]
`);
});

test('added files are sorted', () => {
const store = new EditorStore();
store.setDocuments({
'test/math.test.ts': '',
'.gitignore': '',
'src/math.ts': '',
});

store.addFileOrFolder({ path: 'something.ts', type: 'FILE' });
store.addFileOrFolder({ path: 'another.css', type: 'FILE' });
store.addFileOrFolder({ path: 'no-extension', type: 'FILE' });

expect(store.files.get().map(toFilename)).toMatchInlineSnapshot(`
[
"src/math.ts",
"test/math.test.ts",
".gitignore",
"another.css",
"no-extension",
"something.ts",
]
`);
});

test('added folders are sorted', () => {
const store = new EditorStore();
store.setDocuments({
'test/math.test.ts': '',
'.gitignore': '',
'src/math.ts': '',
});

store.addFileOrFolder({ path: 'src/components', type: 'FOLDER' });
store.addFileOrFolder({ path: 'src/utils', type: 'FOLDER' });
store.addFileOrFolder({ path: 'test/unit', type: 'FOLDER' });
store.addFileOrFolder({ path: 'e2e', type: 'FOLDER' });

expect(store.files.get().map(toFilename)).toMatchInlineSnapshot(`
[
"e2e",
"src/components",
"src/utils",
"src/math.ts",
"test/unit",
"test/math.test.ts",
".gitignore",
]
`);
});

test('empty directories are removed when new content is added', () => {
const store = new EditorStore();
store.setDocuments({
'src/index.ts': '',
});

store.addFileOrFolder({ path: 'src/components', type: 'FOLDER' });

expect(store.files.get().map(toFilename)).toMatchInlineSnapshot(`
[
"src/components",
"src/index.ts",
]
`);

store.addFileOrFolder({ path: 'src/components/FileTree', type: 'FOLDER' });

expect(store.files.get().map(toFilename)).toMatchInlineSnapshot(`
[
"src/components/FileTree",
"src/index.ts",
]
`);
});

function toFilename(file: File) {
return file.path;
}
47 changes: 45 additions & 2 deletions packages/runtime/src/store/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class EditorStore {
files = computed(this.documents, (documents) =>
Object.entries(documents)
.map<File>(([path, doc]) => ({ path, type: doc?.type || 'FILE' }))
.sort(),
.sort(sortFiles),
);
currentDocument = computed([this.documents, this.selectedFile], (documents, selectedFile) => {
if (!selectedFile) {
Expand Down Expand Up @@ -101,7 +101,7 @@ export class EditorStore {

addFileOrFolder(file: File) {
// when adding file or folder to empty folder, remove the empty folder from documents
const emptyFolder = this.files.value?.find((f) => file.path.startsWith(f.path));
const emptyFolder = this.files.get().find((f) => f.type === 'FOLDER' && file.path.startsWith(f.path));

if (emptyFolder && emptyFolder.type === 'FOLDER') {
this.documents.setKey(emptyFolder.path, undefined);
Expand Down Expand Up @@ -169,3 +169,46 @@ export class EditorStore {
};
}
}

function sortFiles(fileA: File, fileB: File) {
const segmentsA = fileA.path.split('/');
const segmentsB = fileB.path.split('/');
const minLength = Math.min(segmentsA.length, segmentsB.length);

for (let i = 0; i < minLength; i++) {
const a = toFileSegment(fileA, segmentsA, i);
const b = toFileSegment(fileB, segmentsB, i);

// folders are always shown before files
if (a.type !== b.type) {
return a.type === 'FOLDER' ? -1 : 1;
}

const comparison = compareString(a.path, b.path);

// either folder name changed or last segments are compared
if (comparison !== 0 || a.isLast || b.isLast) {
return comparison;
}
}

throw new Error(JSON.stringify({ fileA, fileB }));
}

function toFileSegment(file: File, segments: string[], current: number) {
const isLast = segments[current + 1] === undefined;

return { path: segments[current], type: isLast ? file.type : 'FOLDER', isLast };
}

function compareString(a: string, b: string) {
if (a < b) {
return -1;
}

if (a > b) {
return 1;
}

return 0;
}

0 comments on commit 95394df

Please sign in to comment.