isomorphic-jj 1.2.0 → 1.4.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.
- package/dist/index.cjs +141 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +161 -156
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/api/repository.js +141 -136
- package/src/types.d.ts +166 -2
package/dist/index.mjs
CHANGED
|
@@ -4463,14 +4463,14 @@ class UserConfig {
|
|
|
4463
4463
|
*/
|
|
4464
4464
|
|
|
4465
4465
|
|
|
4466
|
-
const __filename$
|
|
4467
|
-
const __dirname$
|
|
4466
|
+
const __filename$4 = fileURLToPath(import.meta.url);
|
|
4467
|
+
const __dirname$4 = path.dirname(__filename$4);
|
|
4468
4468
|
|
|
4469
4469
|
// Determine proto path based on whether we're running from dist or src
|
|
4470
|
-
const inDist$3 = __dirname$
|
|
4470
|
+
const inDist$3 = __dirname$4.includes('/dist') || __dirname$4.includes('\\dist');
|
|
4471
4471
|
const protoDir$3 = inDist$3
|
|
4472
|
-
? path.join(__dirname$
|
|
4473
|
-
: path.join(__dirname$
|
|
4472
|
+
? path.join(__dirname$4, '..', 'src', 'protos')
|
|
4473
|
+
: path.join(__dirname$4, '..', 'protos');
|
|
4474
4474
|
|
|
4475
4475
|
class JJCheckout {
|
|
4476
4476
|
constructor(fs, dir) {
|
|
@@ -4545,14 +4545,14 @@ class JJCheckout {
|
|
|
4545
4545
|
*/
|
|
4546
4546
|
|
|
4547
4547
|
|
|
4548
|
-
const __filename$
|
|
4549
|
-
const __dirname$
|
|
4548
|
+
const __filename$3 = fileURLToPath(import.meta.url);
|
|
4549
|
+
const __dirname$3 = path.dirname(__filename$3);
|
|
4550
4550
|
|
|
4551
4551
|
// Determine proto path based on whether we're running from dist or src
|
|
4552
|
-
const inDist$2 = __dirname$
|
|
4552
|
+
const inDist$2 = __dirname$3.includes('/dist') || __dirname$3.includes('\\dist');
|
|
4553
4553
|
const protoDir$2 = inDist$2
|
|
4554
|
-
? path.join(__dirname$
|
|
4555
|
-
: path.join(__dirname$
|
|
4554
|
+
? path.join(__dirname$3, '..', 'src', 'protos')
|
|
4555
|
+
: path.join(__dirname$3, '..', 'protos');
|
|
4556
4556
|
|
|
4557
4557
|
class JJTreeState {
|
|
4558
4558
|
constructor(fs, dir) {
|
|
@@ -4643,14 +4643,14 @@ class JJTreeState {
|
|
|
4643
4643
|
*/
|
|
4644
4644
|
|
|
4645
4645
|
|
|
4646
|
-
const __filename$
|
|
4647
|
-
const __dirname$
|
|
4646
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
4647
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
4648
4648
|
|
|
4649
4649
|
// Determine proto path based on whether we're running from dist or src
|
|
4650
|
-
const inDist$1 = __dirname$
|
|
4650
|
+
const inDist$1 = __dirname$2.includes('/dist') || __dirname$2.includes('\\dist');
|
|
4651
4651
|
const protoDir$1 = inDist$1
|
|
4652
|
-
? path.join(__dirname$
|
|
4653
|
-
: path.join(__dirname$
|
|
4652
|
+
? path.join(__dirname$2, '..', 'src', 'protos')
|
|
4653
|
+
: path.join(__dirname$2, '..', 'protos');
|
|
4654
4654
|
|
|
4655
4655
|
class JJOperationStore {
|
|
4656
4656
|
constructor(fs, dir) {
|
|
@@ -4767,14 +4767,14 @@ class JJOperationStore {
|
|
|
4767
4767
|
*/
|
|
4768
4768
|
|
|
4769
4769
|
|
|
4770
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
4771
|
-
const __dirname = path.dirname(__filename);
|
|
4770
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
4771
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
4772
4772
|
|
|
4773
4773
|
// Determine proto path based on whether we're running from dist or src
|
|
4774
|
-
const inDist = __dirname.includes('/dist') || __dirname.includes('\\dist');
|
|
4774
|
+
const inDist = __dirname$1.includes('/dist') || __dirname$1.includes('\\dist');
|
|
4775
4775
|
const protoDir = inDist
|
|
4776
|
-
? path.join(__dirname, '..', 'src', 'protos')
|
|
4777
|
-
: path.join(__dirname, '..', 'protos');
|
|
4776
|
+
? path.join(__dirname$1, '..', 'src', 'protos')
|
|
4777
|
+
: path.join(__dirname$1, '..', 'protos');
|
|
4778
4778
|
|
|
4779
4779
|
class JJViewStore {
|
|
4780
4780
|
constructor(fs, dir) {
|
|
@@ -6291,69 +6291,116 @@ async function createJJ(options) {
|
|
|
6291
6291
|
* @param {string[]} [args.paths] - Paths to move between changes (for history operations)
|
|
6292
6292
|
* @returns {Promise<Object>} Returns change object for history operations, file info for file operations
|
|
6293
6293
|
*/
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6294
|
+
/**
|
|
6295
|
+
* Move a file in the working copy
|
|
6296
|
+
*
|
|
6297
|
+
* @param {Object} args - Move file arguments
|
|
6298
|
+
* @param {string} args.from - Source file path
|
|
6299
|
+
* @param {string} args.to - Destination file path
|
|
6300
|
+
* @returns {Promise<Object>} Operation result including from, to paths and file stats
|
|
6301
|
+
*/
|
|
6302
|
+
async moveFile(args) {
|
|
6303
|
+
if (!args.from || typeof args.from !== 'string') {
|
|
6304
|
+
throw new JJError('INVALID_ARGUMENT', 'Missing or invalid from path', {
|
|
6305
|
+
suggestion: 'Provide a valid source file path',
|
|
6306
|
+
provided: { from: args.from, type: typeof args.from },
|
|
6298
6307
|
});
|
|
6299
6308
|
}
|
|
6300
6309
|
|
|
6301
|
-
|
|
6302
|
-
|
|
6310
|
+
if (!args.to || typeof args.to !== 'string') {
|
|
6311
|
+
throw new JJError('INVALID_ARGUMENT', 'Missing or invalid to path', {
|
|
6312
|
+
suggestion: 'Provide a valid destination file path',
|
|
6313
|
+
provided: { to: args.to, type: typeof args.to },
|
|
6314
|
+
});
|
|
6315
|
+
}
|
|
6303
6316
|
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6317
|
+
// Prevent moving to the same location
|
|
6318
|
+
if (args.from === args.to) {
|
|
6319
|
+
throw new JJError('INVALID_OPERATION', 'Source and destination paths are the same', {
|
|
6320
|
+
path: args.from,
|
|
6321
|
+
suggestion: 'Specify a different destination path',
|
|
6322
|
+
});
|
|
6308
6323
|
}
|
|
6309
|
-
},
|
|
6310
6324
|
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
*/
|
|
6318
|
-
_detectHistoryOperation(args) {
|
|
6319
|
-
// Explicit history operation indicators
|
|
6320
|
-
if (args.paths || args.changeId || args.newParent) {
|
|
6321
|
-
return true;
|
|
6325
|
+
// Prevent absolute paths
|
|
6326
|
+
if (args.from.startsWith('/') || args.to.startsWith('/')) {
|
|
6327
|
+
throw new JJError('INVALID_PATH', 'Absolute paths are not allowed', {
|
|
6328
|
+
suggestion: 'Use paths relative to the repository root',
|
|
6329
|
+
provided: { from: args.from, to: args.to },
|
|
6330
|
+
});
|
|
6322
6331
|
}
|
|
6323
6332
|
|
|
6324
|
-
//
|
|
6325
|
-
if (args.from
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6333
|
+
// Prevent parent directory traversal
|
|
6334
|
+
if (args.from.includes('..') || args.to.includes('..')) {
|
|
6335
|
+
throw new JJError('INVALID_PATH', 'Parent directory traversal (..) is not allowed', {
|
|
6336
|
+
suggestion: 'Use paths within the repository',
|
|
6337
|
+
provided: { from: args.from, to: args.to },
|
|
6338
|
+
});
|
|
6339
|
+
}
|
|
6330
6340
|
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
// Users should use explicit { changeId, newParent } for clarity
|
|
6334
|
-
if (fromLooksLikeChangeId && toLooksLikeChangeId) {
|
|
6335
|
-
// This is ambiguous - throw a helpful error
|
|
6336
|
-
throw new JJError('AMBIGUOUS_OPERATION',
|
|
6337
|
-
'Ambiguous move operation: arguments look like change IDs', {
|
|
6338
|
-
suggestion: 'Use { changeId, newParent } for history operations or ensure file paths don\'t match change ID pattern',
|
|
6339
|
-
args,
|
|
6340
|
-
});
|
|
6341
|
-
}
|
|
6341
|
+
const fromPath = `${dir}/${args.from}`;
|
|
6342
|
+
const toPath = `${dir}/${args.to}`;
|
|
6342
6343
|
|
|
6343
|
-
|
|
6344
|
+
// Check if source file exists
|
|
6345
|
+
try {
|
|
6346
|
+
await fs.promises.stat(fromPath);
|
|
6347
|
+
} catch (error) {
|
|
6348
|
+
throw new JJError('FILE_NOT_FOUND', `Source file not found: ${args.from}`, {
|
|
6349
|
+
path: args.from,
|
|
6350
|
+
suggestion: 'Check that the source file exists',
|
|
6351
|
+
});
|
|
6344
6352
|
}
|
|
6345
6353
|
|
|
6346
|
-
|
|
6354
|
+
// Ensure destination directory exists
|
|
6355
|
+
const toDir = toPath.substring(0, toPath.lastIndexOf('/'));
|
|
6356
|
+
try {
|
|
6357
|
+
await fs.promises.mkdir(toDir, { recursive: true });
|
|
6358
|
+
} catch (error) {
|
|
6359
|
+
throw new JJError('FILE_SYSTEM_ERROR', `Failed to create destination directory: ${error.message}`, {
|
|
6360
|
+
path: toDir,
|
|
6361
|
+
error: error.message,
|
|
6362
|
+
});
|
|
6363
|
+
}
|
|
6364
|
+
|
|
6365
|
+
// Move the file
|
|
6366
|
+
try {
|
|
6367
|
+
await fs.promises.rename(fromPath, toPath);
|
|
6368
|
+
} catch (error) {
|
|
6369
|
+
throw new JJError('FILE_SYSTEM_ERROR', `Failed to move file: ${error.message}`, {
|
|
6370
|
+
from: args.from,
|
|
6371
|
+
to: args.to,
|
|
6372
|
+
error: error.message,
|
|
6373
|
+
});
|
|
6374
|
+
}
|
|
6375
|
+
|
|
6376
|
+
// Update working copy tracking
|
|
6377
|
+
await workingCopy.load();
|
|
6378
|
+
await workingCopy.untrackFile(args.from);
|
|
6379
|
+
const stats = await fs.promises.stat(toPath);
|
|
6380
|
+
await workingCopy.trackFile(args.to, {
|
|
6381
|
+
mtime: stats.mtime,
|
|
6382
|
+
size: stats.size,
|
|
6383
|
+
mode: stats.mode,
|
|
6384
|
+
});
|
|
6385
|
+
|
|
6386
|
+
return {
|
|
6387
|
+
from: args.from,
|
|
6388
|
+
to: args.to,
|
|
6389
|
+
size: stats.size,
|
|
6390
|
+
mode: stats.mode,
|
|
6391
|
+
mtime: stats.mtime,
|
|
6392
|
+
};
|
|
6347
6393
|
},
|
|
6348
6394
|
|
|
6349
6395
|
/**
|
|
6350
|
-
* Move
|
|
6396
|
+
* Move (rebase) a change to a new parent
|
|
6351
6397
|
*
|
|
6352
|
-
* @
|
|
6353
|
-
* @param {
|
|
6398
|
+
* @param {Object} args - Move change arguments
|
|
6399
|
+
* @param {string} args.changeId - Change ID to move (also accepts 'from' or 'source')
|
|
6400
|
+
* @param {string} args.newParent - New parent change ID (also accepts 'to' or 'destination')
|
|
6354
6401
|
* @returns {Promise<Object>} Updated change object
|
|
6355
6402
|
*/
|
|
6356
|
-
async
|
|
6403
|
+
async moveChange(args) {
|
|
6357
6404
|
await graph.load();
|
|
6358
6405
|
|
|
6359
6406
|
// Support multiple parameter names for flexibility
|
|
@@ -6441,110 +6488,62 @@ async function createJJ(options) {
|
|
|
6441
6488
|
},
|
|
6442
6489
|
|
|
6443
6490
|
/**
|
|
6444
|
-
*
|
|
6445
|
-
*
|
|
6446
|
-
* @private
|
|
6447
|
-
* @param {Object} args - Move arguments
|
|
6448
|
-
* @returns {Promise<Object>} Operation result including from, to paths and file stats
|
|
6491
|
+
* @deprecated Use moveFile() for files or moveChange() for history operations
|
|
6492
|
+
* Move operation - delegates to moveFile or moveChange based on arguments
|
|
6449
6493
|
*/
|
|
6450
|
-
async
|
|
6451
|
-
if (!args
|
|
6452
|
-
throw new JJError('INVALID_ARGUMENT', 'Missing or invalid
|
|
6453
|
-
suggestion: '
|
|
6454
|
-
provided: { from: args.from, type: typeof args.from },
|
|
6455
|
-
});
|
|
6456
|
-
}
|
|
6457
|
-
|
|
6458
|
-
if (!args.to || typeof args.to !== 'string') {
|
|
6459
|
-
throw new JJError('INVALID_ARGUMENT', 'Missing or invalid to path', {
|
|
6460
|
-
suggestion: 'Provide a valid destination file path',
|
|
6461
|
-
provided: { to: args.to, type: typeof args.to },
|
|
6494
|
+
async move(args) {
|
|
6495
|
+
if (!args || typeof args !== 'object') {
|
|
6496
|
+
throw new JJError('INVALID_ARGUMENT', 'Missing or invalid arguments', {
|
|
6497
|
+
suggestion: 'Use moveFile({ from, to }) for files or moveChange({ changeId, newParent }) for history',
|
|
6462
6498
|
});
|
|
6463
6499
|
}
|
|
6464
6500
|
|
|
6465
|
-
//
|
|
6466
|
-
|
|
6467
|
-
throw new JJError('INVALID_OPERATION', 'Source and destination paths are the same', {
|
|
6468
|
-
path: args.from,
|
|
6469
|
-
suggestion: 'Specify a different destination path',
|
|
6470
|
-
});
|
|
6471
|
-
}
|
|
6501
|
+
// Detect operation type based on arguments
|
|
6502
|
+
const isHistoryOp = this._detectHistoryOperation(args);
|
|
6472
6503
|
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
provided: { from: args.from, to: args.to },
|
|
6478
|
-
});
|
|
6504
|
+
if (isHistoryOp) {
|
|
6505
|
+
return await this.moveChange(args);
|
|
6506
|
+
} else {
|
|
6507
|
+
return await this.moveFile(args);
|
|
6479
6508
|
}
|
|
6509
|
+
},
|
|
6480
6510
|
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6511
|
+
/**
|
|
6512
|
+
* Detect if move operation is for history (rebase) or files
|
|
6513
|
+
*
|
|
6514
|
+
* @private
|
|
6515
|
+
* @param {Object} args - Move arguments
|
|
6516
|
+
* @returns {boolean} True if history operation, false if file operation
|
|
6517
|
+
*/
|
|
6518
|
+
_detectHistoryOperation(args) {
|
|
6519
|
+
// Explicit history operation indicators
|
|
6520
|
+
if (args.paths || args.changeId || args.newParent) {
|
|
6521
|
+
return true;
|
|
6487
6522
|
}
|
|
6488
6523
|
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
} catch (error) {
|
|
6496
|
-
throw new JJError('FILE_NOT_FOUND', `Source file not found: ${args.from}`, {
|
|
6497
|
-
path: args.from,
|
|
6498
|
-
fullPath: fromPath,
|
|
6499
|
-
suggestion: 'Check that the file exists',
|
|
6500
|
-
});
|
|
6501
|
-
}
|
|
6524
|
+
// If only from/to are present, check if they look like change IDs
|
|
6525
|
+
if (args.from && args.to && !args.changeId && !args.newParent && !args.paths) {
|
|
6526
|
+
// Change IDs are 32-character hex strings
|
|
6527
|
+
const changeIdPattern = /^[0-9a-f]{32}$/;
|
|
6528
|
+
const fromLooksLikeChangeId = changeIdPattern.test(args.from);
|
|
6529
|
+
const toLooksLikeChangeId = changeIdPattern.test(args.to);
|
|
6502
6530
|
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
`Failed to create destination directory: ${dirPath}`, {
|
|
6513
|
-
directory: dirPath,
|
|
6514
|
-
originalError: error.message,
|
|
6531
|
+
// If both look like change IDs, it's likely a history operation
|
|
6532
|
+
// However, we err on the side of file operations to be safe
|
|
6533
|
+
// Users should use explicit { changeId, newParent } for clarity
|
|
6534
|
+
if (fromLooksLikeChangeId && toLooksLikeChangeId) {
|
|
6535
|
+
// This is ambiguous - throw a helpful error
|
|
6536
|
+
throw new JJError('AMBIGUOUS_OPERATION',
|
|
6537
|
+
'Ambiguous move operation: arguments look like change IDs', {
|
|
6538
|
+
suggestion: 'Use { changeId, newParent } for history operations or ensure file paths don\'t match change ID pattern',
|
|
6539
|
+
args,
|
|
6515
6540
|
});
|
|
6516
6541
|
}
|
|
6517
|
-
}
|
|
6518
6542
|
|
|
6519
|
-
|
|
6520
|
-
try {
|
|
6521
|
-
await fs.promises.rename(fromPath, toPath);
|
|
6522
|
-
} catch (error) {
|
|
6523
|
-
throw new JJError('FILE_MOVE_FAILED', `Failed to move file: ${error.message}`, {
|
|
6524
|
-
from: args.from,
|
|
6525
|
-
to: args.to,
|
|
6526
|
-
originalError: error.message,
|
|
6527
|
-
});
|
|
6543
|
+
return false; // Treat as file operation
|
|
6528
6544
|
}
|
|
6529
6545
|
|
|
6530
|
-
|
|
6531
|
-
await workingCopy.load();
|
|
6532
|
-
await workingCopy.untrackFile(args.from);
|
|
6533
|
-
const stats = await fs.promises.stat(toPath);
|
|
6534
|
-
await workingCopy.trackFile(args.to, {
|
|
6535
|
-
mtime: stats.mtime,
|
|
6536
|
-
size: stats.size,
|
|
6537
|
-
mode: stats.mode,
|
|
6538
|
-
});
|
|
6539
|
-
|
|
6540
|
-
// Return useful information about the move operation
|
|
6541
|
-
return {
|
|
6542
|
-
from: args.from,
|
|
6543
|
-
to: args.to,
|
|
6544
|
-
size: stats.size,
|
|
6545
|
-
mode: stats.mode,
|
|
6546
|
-
mtime: stats.mtime,
|
|
6547
|
-
};
|
|
6546
|
+
return false;
|
|
6548
6547
|
},
|
|
6549
6548
|
|
|
6550
6549
|
/**
|
|
@@ -6620,6 +6619,11 @@ async function createJJ(options) {
|
|
|
6620
6619
|
change.timestamp = new Date().toISOString();
|
|
6621
6620
|
}
|
|
6622
6621
|
|
|
6622
|
+
// Update metadata
|
|
6623
|
+
if (args.metadata !== undefined) {
|
|
6624
|
+
change.metadata = args.metadata;
|
|
6625
|
+
}
|
|
6626
|
+
|
|
6623
6627
|
// Only snapshot files if describing working copy
|
|
6624
6628
|
if (isWorkingCopy) {
|
|
6625
6629
|
// Snapshot current file contents for conflict detection
|
|
@@ -7224,10 +7228,11 @@ async function createJJ(options) {
|
|
|
7224
7228
|
* @param {Object} [args={}] - Arguments
|
|
7225
7229
|
* @param {string} [args.message] - Description for current change
|
|
7226
7230
|
* @param {Object} [args.author] - Author for current change
|
|
7231
|
+
* @param {Object} [args.metadata] - Metadata to attach to the change
|
|
7227
7232
|
* @returns {Promise<Object>} The newly created change
|
|
7228
7233
|
*/
|
|
7229
7234
|
async commit(args = {}) {
|
|
7230
|
-
await this.describe({ message: args.message, author: args.author });
|
|
7235
|
+
await this.describe({ message: args.message, author: args.author, metadata: args.metadata });
|
|
7231
7236
|
return await this.new({ message: args.nextMessage });
|
|
7232
7237
|
},
|
|
7233
7238
|
|
|
@@ -8051,7 +8056,7 @@ async function createJJ(options) {
|
|
|
8051
8056
|
* });
|
|
8052
8057
|
*/
|
|
8053
8058
|
async rebase(args) {
|
|
8054
|
-
return await this.
|
|
8059
|
+
return await this.moveChange(args);
|
|
8055
8060
|
},
|
|
8056
8061
|
|
|
8057
8062
|
/**
|