johankit 0.0.2

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.
Files changed (59) hide show
  1. package/README.md +115 -0
  2. package/dist/cli/commands/copy.js +24 -0
  3. package/dist/cli/commands/paste.js +40 -0
  4. package/dist/cli/commands/prompt.js +57 -0
  5. package/dist/cli/commands/sync.js +84 -0
  6. package/dist/core/clipboard.js +54 -0
  7. package/dist/core/config.js +52 -0
  8. package/dist/core/diff.js +29 -0
  9. package/dist/core/git.js +43 -0
  10. package/dist/core/scan.js +67 -0
  11. package/dist/core/schema.js +41 -0
  12. package/dist/core/validation.js +24 -0
  13. package/dist/core/write.js +24 -0
  14. package/dist/index.js +54 -0
  15. package/dist/tests/cli/commands/copy.test.js +47 -0
  16. package/dist/tests/cli/commands/paste.test.js +41 -0
  17. package/dist/tests/cli/commands/prompt.test.js +37 -0
  18. package/dist/tests/cli/commands/sync.test.js +47 -0
  19. package/dist/tests/core/clipboard.test.js +20 -0
  20. package/dist/tests/core/config.test.js +23 -0
  21. package/dist/tests/core/diff.test.js +24 -0
  22. package/dist/tests/core/git.test.js +11 -0
  23. package/dist/tests/core/scan.test.js +16 -0
  24. package/dist/tests/core/schema.test.js +13 -0
  25. package/dist/tests/core/validation.test.js +13 -0
  26. package/dist/tests/core/write.test.js +41 -0
  27. package/dist/types.js +2 -0
  28. package/jest.config.js +6 -0
  29. package/package-lock.json +250 -0
  30. package/package.json +30 -0
  31. package/src/cli/commands/copy.ts +22 -0
  32. package/src/cli/commands/paste.ts +43 -0
  33. package/src/cli/commands/prompt.ts +55 -0
  34. package/src/cli/commands/sync.ts +88 -0
  35. package/src/core/clipboard.ts +56 -0
  36. package/src/core/config.ts +50 -0
  37. package/src/core/diff.ts +31 -0
  38. package/src/core/git.ts +39 -0
  39. package/src/core/scan.ts +70 -0
  40. package/src/core/schema.ts +41 -0
  41. package/src/core/validation.ts +28 -0
  42. package/src/core/write.ts +26 -0
  43. package/src/index.ts +61 -0
  44. package/src/tests/cli/commands/copy.test.ts +26 -0
  45. package/src/tests/cli/commands/paste.test.ts +19 -0
  46. package/src/tests/cli/commands/prompt.test.ts +14 -0
  47. package/src/tests/cli/commands/sync.test.ts +26 -0
  48. package/src/tests/core/clipboard.test.ts +21 -0
  49. package/src/tests/core/config.test.ts +21 -0
  50. package/src/tests/core/diff.test.ts +22 -0
  51. package/src/tests/core/git.test.ts +11 -0
  52. package/src/tests/core/scan.test.ts +13 -0
  53. package/src/tests/core/schema.test.ts +13 -0
  54. package/src/tests/core/validation.test.ts +13 -0
  55. package/src/tests/core/write.test.ts +15 -0
  56. package/src/types.ts +14 -0
  57. package/tsconfig.json +12 -0
  58. package/types.js +2 -0
  59. package/types.ts +11 -0
@@ -0,0 +1,19 @@
1
+ import { paste } from '../../../cli/commands/paste';
2
+ import * as clipboard from '../../../core/clipboard';
3
+ import * as write from '../../../core/write';
4
+
5
+ jest.mock('../../../core/clipboard');
6
+ jest.mock('../../../core/write');
7
+
8
+ describe('paste', () => {
9
+ it('should write files from clipboard JSON', async () => {
10
+ (clipboard.readClipboard as jest.Mock).mockResolvedValue(JSON.stringify([{ path: 'a.txt', content: 'hi' }]));
11
+ await paste('dir');
12
+ expect(write.writeFiles).toHaveBeenCalledWith('dir', [{ path: 'a.txt', content: 'hi' }], true);
13
+ });
14
+
15
+ it('should throw on invalid JSON', async () => {
16
+ (clipboard.readClipboard as jest.Mock).mockResolvedValue('not json');
17
+ await expect(paste('dir')).rejects.toThrow('Clipboard content is not valid JSON');
18
+ });
19
+ });
@@ -0,0 +1,14 @@
1
+ import { prompt } from '../../../cli/commands/prompt';
2
+ import * as scan from '../../../core/scan';
3
+ import * as clipboard from '../../../core/clipboard';
4
+
5
+ jest.mock('../../../core/scan');
6
+ jest.mock('../../../core/clipboard');
7
+
8
+ describe('prompt', () => {
9
+ it('should generate prompt with snapshot and copy to clipboard', async () => {
10
+ (scan.scanDir as jest.Mock).mockReturnValue([{ path: 'file.js', content: 'console.log(1)' }]);
11
+ await prompt('.', 'do something');
12
+ expect(clipboard.copyToClipboard).toHaveBeenCalled();
13
+ });
14
+ });
@@ -0,0 +1,26 @@
1
+ import { sync } from '../../../cli/commands/sync';
2
+ import * as scan from '../../../core/scan';
3
+ import * as clipboard from '../../../core/clipboard';
4
+ import * as diff from '../../../core/diff';
5
+ import * as validation from '../../../core/validation';
6
+
7
+ jest.mock('../../../core/scan');
8
+ jest.mock('../../../core/clipboard');
9
+ jest.mock('../../../core/diff');
10
+ jest.mock('../../../core/validation');
11
+
12
+ describe('sync', () => {
13
+ it('should apply patches and update clipboard', async () => {
14
+ (scan.scanDir as jest.Mock).mockReturnValue([]);
15
+ (clipboard.copyToClipboard as jest.Mock).mockResolvedValue(undefined);
16
+ (validation.validatePatches as jest.Mock).mockImplementation(p => p);
17
+
18
+ const input = JSON.stringify([{ type: 'create', path: 'a.txt', content: 'x' }]);
19
+ process.stdin.push(input);
20
+ process.stdin.push(null);
21
+
22
+ await sync('.');
23
+ expect(diff.applyDiff).toHaveBeenCalled();
24
+ expect(clipboard.copyToClipboard).toHaveBeenCalledTimes(2);
25
+ });
26
+ });
@@ -0,0 +1,21 @@
1
+ import { copyToClipboard, readClipboard } from '../../../core/clipboard';
2
+ import { spawn } from 'child_process';
3
+
4
+ jest.mock('child_process', () => ({
5
+ spawn: jest.fn(() => ({
6
+ stdin: { write: jest.fn(), end: jest.fn() },
7
+ stdout: { on: jest.fn() },
8
+ stderr: { on: jest.fn() },
9
+ on: jest.fn((event, cb) => { if (event === 'close') cb(0); })
10
+ }))
11
+ }));
12
+
13
+ describe('clipboard', () => {
14
+ it('should copy to clipboard', async () => {
15
+ await expect(copyToClipboard('hi')).resolves.toBeUndefined();
16
+ });
17
+
18
+ it('should read from clipboard', async () => {
19
+ await expect(readClipboard()).resolves.toBe('');
20
+ });
21
+ });
@@ -0,0 +1,21 @@
1
+ import { loadConfig } from '../../../core/config';
2
+ import fs from 'fs';
3
+ import { load as yamlLoad } from 'js-yaml';
4
+
5
+ jest.mock('fs');
6
+ jest.mock('js-yaml');
7
+
8
+ describe('loadConfig', () => {
9
+ it('should return defaults if file missing', () => {
10
+ (fs.readFileSync as jest.Mock).mockImplementation(() => { throw { code: 'ENOENT' }; });
11
+ const config = loadConfig('.');
12
+ expect(config.ignore).toContain('.git');
13
+ });
14
+
15
+ it('should merge user ignore', () => {
16
+ (fs.readFileSync as jest.Mock).mockReturnValue('ignore:\n - test');
17
+ (yamlLoad as jest.Mock).mockReturnValue({ ignore: ['test'] });
18
+ const config = loadConfig('.');
19
+ expect(config.ignore).toContain('test');
20
+ });
21
+ });
@@ -0,0 +1,22 @@
1
+ import { applyDiff, DiffPatch } from '../../../core/diff';
2
+ import fs from 'fs';
3
+
4
+ jest.mock('fs');
5
+
6
+ describe('applyDiff', () => {
7
+ it('should handle create and modify', () => {
8
+ const patches: DiffPatch[] = [
9
+ { type: 'create', path: 'a.txt', content: 'x' },
10
+ { type: 'modify', path: 'b.txt', content: 'y' }
11
+ ];
12
+ applyDiff('.', patches);
13
+ expect(fs.writeFileSync).toHaveBeenCalledTimes(2);
14
+ });
15
+
16
+ it('should handle delete', () => {
17
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
18
+ const patches: DiffPatch[] = [{ type: 'delete', path: 'c.txt' }];
19
+ applyDiff('.', patches);
20
+ expect(fs.unlinkSync).toHaveBeenCalledWith('./c.txt');
21
+ });
22
+ });
@@ -0,0 +1,11 @@
1
+ import { ensureGitCommit } from '../../../core/git';
2
+ import { execSync } from 'child_process';
3
+
4
+ jest.mock('child_process');
5
+
6
+ describe('ensureGitCommit', () => {
7
+ it('should call git commands without crashing', () => {
8
+ (execSync as jest.Mock).mockImplementation(() => '');
9
+ expect(() => ensureGitCommit()).not.toThrow();
10
+ });
11
+ });
@@ -0,0 +1,13 @@
1
+ import { scanDir } from '../../../core/scan';
2
+ import fs from 'fs';
3
+
4
+ jest.mock('fs');
5
+
6
+ describe('scanDir', () => {
7
+ it('should scan files with default ignores', () => {
8
+ (fs.readdirSync as jest.Mock).mockReturnValue([{ name: 'a.txt', isDirectory: () => false }]);
9
+ (fs.readFileSync as jest.Mock).mockReturnValue('content');
10
+ const files = scanDir('.');
11
+ expect(files[0].path).toBe('a.txt');
12
+ });
13
+ });
@@ -0,0 +1,13 @@
1
+ import { validatePatches } from '../../../core/schema';
2
+
3
+ describe('validatePatches', () => {
4
+ it('should validate correct patches', () => {
5
+ const patches = [{ type: 'create', path: 'a.txt', content: 'x' }];
6
+ expect(validatePatches(patches)).toEqual(patches);
7
+ });
8
+
9
+ it('should throw on invalid patches', () => {
10
+ const patches = [{ type: 'invalid', path: 'a.txt', content: 'x' }];
11
+ expect(() => validatePatches(patches)).toThrow();
12
+ });
13
+ });
@@ -0,0 +1,13 @@
1
+ import { validatePatches } from '../../../core/validation';
2
+
3
+ describe('validation', () => {
4
+ it('validates correct array', () => {
5
+ const input = [{ type: 'create', path: 'a.txt', content: 'x' }];
6
+ expect(validatePatches(input)).toEqual(input);
7
+ });
8
+
9
+ it('throws on missing content', () => {
10
+ const input = [{ type: 'create', path: 'a.txt' }];
11
+ expect(() => validatePatches(input)).toThrow();
12
+ });
13
+ });
@@ -0,0 +1,15 @@
1
+ import { writeFiles } from '../../../core/write';
2
+ import fs from 'fs';
3
+ import * as git from '../../../core/git';
4
+
5
+ jest.mock('fs');
6
+ jest.mock('../../../core/git');
7
+
8
+ describe('writeFiles', () => {
9
+ it('should write files and commit', () => {
10
+ const files = [{ path: 'a.txt', content: 'x' }];
11
+ writeFiles('.', files, true);
12
+ expect(fs.writeFileSync).toHaveBeenCalledWith('./a.txt', 'x', 'utf8');
13
+ expect(git.ensureGitCommit).toHaveBeenCalled();
14
+ });
15
+ });
package/src/types.ts ADDED
@@ -0,0 +1,14 @@
1
+ // src/types.ts
2
+ export interface FileSnapshot {
3
+ path: string;
4
+ content: string;
5
+ }
6
+
7
+ export interface ScanOptions {
8
+ extensions?: string[]; // ['.js', '.ts', '.css']
9
+ // A opção 'ignore' foi movida para o arquivo de configuração e 'loadConfig'
10
+ }
11
+
12
+ export interface Config {
13
+ ignore: string[]; // Patterns de arquivos/diretórios a ignorar
14
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "esModuleInterop": true,
9
+ "strict": true,
10
+ "skipLibCheck": true
11
+ }
12
+ }
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ // src/types.ts
2
+ export interface FileSnapshot {
3
+ path: string;
4
+ content: string;
5
+ type?: "modify" | "create" | "delete";
6
+ }
7
+
8
+ export interface ScanOptions {
9
+ extensions?: string[]; // ['.js', '.ts', '.css']
10
+ ignore?: string[];
11
+ }