@marteye/studiojs 1.1.24 → 1.1.26
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.d.ts +263 -109
- package/dist/index.esm.js +381 -10
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +384 -9
- package/dist/index.js.map +1 -1
- package/dist/resources/applications.d.ts +90 -0
- package/dist/resources/files.d.ts +6 -2
- package/dist/resources/lots.d.ts +1 -0
- package/dist/resources.d.ts +14 -1
- package/dist/studio.d.ts +14 -1
- package/dist/types.d.ts +40 -0
- package/dist/utils/eartag.d.ts +2 -2
- package/dist/utils/lots.d.ts +10 -0
- package/dist/utils/multipart-upload.d.ts +23 -3
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ function SimpleHttpClient(baseUrl, apiKey, fetch, defaultTimeout, debug = false)
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Path: studiojs/src/resources/markets.ts
|
|
74
|
-
function create$
|
|
74
|
+
function create$d(_) {
|
|
75
75
|
const actions = {
|
|
76
76
|
/***
|
|
77
77
|
* This is used to construct the action from the request body
|
|
@@ -101,7 +101,7 @@ function create$c(_) {
|
|
|
101
101
|
return actions;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
function create$
|
|
104
|
+
function create$c(httpClient) {
|
|
105
105
|
return {
|
|
106
106
|
list: async (marketId) => {
|
|
107
107
|
return httpClient.get(`/${marketId}/adjustments`);
|
|
@@ -112,6 +112,72 @@ function create$b(httpClient) {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
function create$b(httpClient) {
|
|
116
|
+
let applications = {
|
|
117
|
+
/**
|
|
118
|
+
* List applications for a market with optional filtering
|
|
119
|
+
* @param marketId - ID of the market
|
|
120
|
+
* @param options - Optional query parameters for filtering and pagination
|
|
121
|
+
* @returns Paginated list of applications
|
|
122
|
+
*/
|
|
123
|
+
list: async (marketId, options) => {
|
|
124
|
+
return httpClient.get(`/${marketId}/applications`, options);
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* Get a single application by ID
|
|
128
|
+
* @param marketId - ID of the market
|
|
129
|
+
* @param applicationId - ID of the application
|
|
130
|
+
* @returns The application details
|
|
131
|
+
*/
|
|
132
|
+
get: async (marketId, applicationId) => {
|
|
133
|
+
return httpClient.get(`/${marketId}/applications/${applicationId}`);
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* Create a new application
|
|
137
|
+
* @param marketId - ID of the market
|
|
138
|
+
* @param applicationData - The application data
|
|
139
|
+
* @returns The created application
|
|
140
|
+
*/
|
|
141
|
+
create: async (marketId, applicationData) => {
|
|
142
|
+
return httpClient.post(`/${marketId}/applications`, applicationData);
|
|
143
|
+
},
|
|
144
|
+
/**
|
|
145
|
+
* Update an existing application
|
|
146
|
+
* @param marketId - ID of the market
|
|
147
|
+
* @param applicationId - ID of the application to update
|
|
148
|
+
* @param updateData - The fields to update
|
|
149
|
+
* @returns The updated application
|
|
150
|
+
* @throws Error if the application is already approved or rejected
|
|
151
|
+
*/
|
|
152
|
+
update: async (marketId, applicationId, updateData) => {
|
|
153
|
+
return httpClient.post(`/${marketId}/applications/${applicationId}`, updateData);
|
|
154
|
+
},
|
|
155
|
+
/**
|
|
156
|
+
* Approve an application
|
|
157
|
+
* @param marketId - ID of the market
|
|
158
|
+
* @param applicationId - ID of the application to approve
|
|
159
|
+
* @param notes - Optional notes for the approval
|
|
160
|
+
* @returns The approved application
|
|
161
|
+
* @throws Error if the application is not in pending status
|
|
162
|
+
*/
|
|
163
|
+
approve: async (marketId, applicationId, notes) => {
|
|
164
|
+
return httpClient.post(`/${marketId}/applications/${applicationId}/approve`, { notes });
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* Reject an application
|
|
168
|
+
* @param marketId - ID of the market
|
|
169
|
+
* @param applicationId - ID of the application to reject
|
|
170
|
+
* @param notes - Optional notes for the rejection
|
|
171
|
+
* @returns The rejected application
|
|
172
|
+
* @throws Error if the application is not in pending status
|
|
173
|
+
*/
|
|
174
|
+
reject: async (marketId, applicationId, notes) => {
|
|
175
|
+
return httpClient.post(`/${marketId}/applications/${applicationId}/reject`, { notes });
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
return applications;
|
|
179
|
+
}
|
|
180
|
+
|
|
115
181
|
// Path: studiojs/src/resources/markets.ts
|
|
116
182
|
function create$a(httpClient) {
|
|
117
183
|
let customers = {
|
|
@@ -4558,7 +4624,12 @@ z.object({
|
|
|
4558
4624
|
suffix: z.string().min(1, { message: "Suffix Type is required" }),
|
|
4559
4625
|
});
|
|
4560
4626
|
// Adding Sizes here will make more end points in the mainConfig object
|
|
4561
|
-
const IMAGE_SIZES_VALUES$1 = [
|
|
4627
|
+
const IMAGE_SIZES_VALUES$1 = [
|
|
4628
|
+
"thumbnail",
|
|
4629
|
+
"small",
|
|
4630
|
+
"medium",
|
|
4631
|
+
"large",
|
|
4632
|
+
];
|
|
4562
4633
|
const VIDEO_TASKS_VALUES$1 = ["compressed", "thumbnail"];
|
|
4563
4634
|
z.enum(VIDEO_TASKS_VALUES$1);
|
|
4564
4635
|
z.enum(IMAGE_SIZES_VALUES$1);
|
|
@@ -4568,12 +4639,29 @@ const UPLOAD_PATHS = {
|
|
|
4568
4639
|
FINISH_UPLOAD: "finishMultipartUpload",
|
|
4569
4640
|
CANCEL_UPLOAD: "cancelUpload",
|
|
4570
4641
|
DELETE_UPLOAD: "deleteUpload",
|
|
4642
|
+
UPLOAD_SINGLE_FILE: "upload",
|
|
4571
4643
|
};
|
|
4572
4644
|
/**
|
|
4573
4645
|
|--------------------------------------------------
|
|
4574
4646
|
| Helper Functions
|
|
4575
4647
|
|--------------------------------------------------
|
|
4576
4648
|
*/
|
|
4649
|
+
const MIME_TYPE_MAP = {
|
|
4650
|
+
png: "image/png",
|
|
4651
|
+
jpg: "image/jpeg",
|
|
4652
|
+
jpeg: "image/jpeg",
|
|
4653
|
+
mp4: "video/mp4",
|
|
4654
|
+
mov: "video/quicktime",
|
|
4655
|
+
qt: "video/quicktime",
|
|
4656
|
+
};
|
|
4657
|
+
/**
|
|
4658
|
+
|--------------------------------------------------
|
|
4659
|
+
| Make a File Path
|
|
4660
|
+
|--------------------------------------------------
|
|
4661
|
+
*/
|
|
4662
|
+
function createFilePath(marketId, saleId, lotId, attributeId, fileName) {
|
|
4663
|
+
return `/${marketId}/${saleId}/${lotId}/${attributeId}/${fileName}`;
|
|
4664
|
+
}
|
|
4577
4665
|
const getHeaders = (mimeType, bucket = "raw", token) => {
|
|
4578
4666
|
const headers = new Headers();
|
|
4579
4667
|
headers.append("mbtype", bucket);
|
|
@@ -4595,7 +4683,7 @@ const startUpload = async ({ fileName, fileMimeType, fileExtension, token, optio
|
|
|
4595
4683
|
var _a;
|
|
4596
4684
|
const headers = getHeaders(fileMimeType, (_a = options.options) === null || _a === void 0 ? void 0 : _a.bucket, token);
|
|
4597
4685
|
const formData = new FormData();
|
|
4598
|
-
const filePath =
|
|
4686
|
+
const filePath = createFilePath(options.marketId, options.saleId, options.lotId, options.attributeId, `${fileName}.${fileExtension}`);
|
|
4599
4687
|
formData.append("filePath", filePath);
|
|
4600
4688
|
headers.append("Authorization", `Bearer ${token}`);
|
|
4601
4689
|
let uploadIdResponse = await fetch(new URL(`${BASE_CF_URL}/${UPLOAD_PATHS.START_UPLOAD}`), {
|
|
@@ -4762,7 +4850,7 @@ const deleteUpload = async (fileUrl, token) => {
|
|
|
4762
4850
|
* @returns {Promise<MediaFinishUploadResponse>}
|
|
4763
4851
|
* @throws {Error} When upload fails
|
|
4764
4852
|
*/
|
|
4765
|
-
const
|
|
4853
|
+
const uploadMultipartFile = async (input, token) => {
|
|
4766
4854
|
var _a, _b, _c, _d, _e;
|
|
4767
4855
|
let uploadId = "";
|
|
4768
4856
|
let filePath = "";
|
|
@@ -4866,12 +4954,61 @@ const uploadFile = async (input, token) => {
|
|
|
4866
4954
|
throw new Error("Upload failed and canceled " + error);
|
|
4867
4955
|
}
|
|
4868
4956
|
};
|
|
4957
|
+
const uploadSingleFile = async (input, token) => {
|
|
4958
|
+
const { file, filePath, uploadConfig } = input;
|
|
4959
|
+
let fileMimeType = "";
|
|
4960
|
+
let destinationPath = "";
|
|
4961
|
+
let fileName = "";
|
|
4962
|
+
let fileExtension = "";
|
|
4963
|
+
if (!filePath && !file) {
|
|
4964
|
+
throw new Error("Either filePath or file must be provided");
|
|
4965
|
+
}
|
|
4966
|
+
if (filePath && file) {
|
|
4967
|
+
throw new Error("Only one of filePath or file can be provided");
|
|
4968
|
+
}
|
|
4969
|
+
// We perform a copy form one file to another
|
|
4970
|
+
if (filePath) {
|
|
4971
|
+
fileName = filePath.split("/").pop() || "";
|
|
4972
|
+
fileExtension = fileName.split(".").pop() || "";
|
|
4973
|
+
fileMimeType = MIME_TYPE_MAP[fileExtension] || "";
|
|
4974
|
+
destinationPath = createFilePath(uploadConfig.marketId, uploadConfig.saleId, uploadConfig.lotId, uploadConfig.attributeId, `${fileName}`);
|
|
4975
|
+
}
|
|
4976
|
+
// We upload a single File
|
|
4977
|
+
if (file) {
|
|
4978
|
+
fileName = file.name.replace(/\.[^/.]+$/, "");
|
|
4979
|
+
fileExtension = file.name.split(".").pop() || "";
|
|
4980
|
+
fileMimeType = file.type;
|
|
4981
|
+
destinationPath = createFilePath(uploadConfig.marketId, uploadConfig.saleId, uploadConfig.lotId, uploadConfig.attributeId, `${fileName}.${fileExtension}`);
|
|
4982
|
+
}
|
|
4983
|
+
// Construct the Fetch Request
|
|
4984
|
+
const uploadUrl = new URL(`${BASE_CF_URL}/${UPLOAD_PATHS.UPLOAD_SINGLE_FILE}`);
|
|
4985
|
+
const headers = new Headers();
|
|
4986
|
+
headers.append("mbtype", "raw");
|
|
4987
|
+
headers.append("Authorization", `Bearer ${token}`);
|
|
4988
|
+
headers.append("mmimetype", fileMimeType);
|
|
4989
|
+
const formData = new FormData();
|
|
4990
|
+
filePath && formData.append("existingFilePath", filePath);
|
|
4991
|
+
destinationPath && formData.append("filePath", destinationPath);
|
|
4992
|
+
file && formData.append("file", file);
|
|
4993
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
4994
|
+
headers: headers,
|
|
4995
|
+
method: "POST",
|
|
4996
|
+
body: formData,
|
|
4997
|
+
});
|
|
4998
|
+
if (!uploadResponse.ok) {
|
|
4999
|
+
throw new Error("Failed to upload single file");
|
|
5000
|
+
}
|
|
5001
|
+
return (await uploadResponse.json());
|
|
5002
|
+
};
|
|
4869
5003
|
|
|
4870
5004
|
// Multipart Upload for Media to the MARTEYE Media Service
|
|
4871
5005
|
function create$9() {
|
|
4872
5006
|
const files = {
|
|
4873
|
-
|
|
4874
|
-
return await
|
|
5007
|
+
uploadSingleFile: async (input, token) => {
|
|
5008
|
+
return await uploadSingleFile(input, token);
|
|
5009
|
+
},
|
|
5010
|
+
uploadMultipartFile: async (input, token) => {
|
|
5011
|
+
return await uploadMultipartFile(input, token);
|
|
4875
5012
|
},
|
|
4876
5013
|
deleteFile: async (fileUrl, token) => {
|
|
4877
5014
|
return await deleteUpload(fileUrl, token);
|
|
@@ -5044,9 +5181,10 @@ function resources(httpClient) {
|
|
|
5044
5181
|
lots: create$7(httpClient),
|
|
5045
5182
|
lotitems: create$8(httpClient),
|
|
5046
5183
|
webhooks: create(),
|
|
5047
|
-
actions: create$
|
|
5184
|
+
actions: create$d(),
|
|
5185
|
+
applications: create$b(httpClient),
|
|
5048
5186
|
settings: create$2(httpClient),
|
|
5049
|
-
adjustments: create$
|
|
5187
|
+
adjustments: create$c(httpClient),
|
|
5050
5188
|
productCodes: create$5(httpClient),
|
|
5051
5189
|
taxRates: create$1(httpClient),
|
|
5052
5190
|
customers: create$a(httpClient),
|
|
@@ -5216,9 +5354,246 @@ function createAppManifest(appConfig) {
|
|
|
5216
5354
|
};
|
|
5217
5355
|
}
|
|
5218
5356
|
|
|
5357
|
+
class EarTag {
|
|
5358
|
+
static get countryCodesByNumber() {
|
|
5359
|
+
let reversed = {};
|
|
5360
|
+
for (const key of Object.keys(EarTag.countryCodes)) {
|
|
5361
|
+
reversed[EarTag.countryCodes[key]] = key;
|
|
5362
|
+
}
|
|
5363
|
+
return reversed;
|
|
5364
|
+
}
|
|
5365
|
+
normalisedCountryCode(countryCode) {
|
|
5366
|
+
if (!countryCode || typeof countryCode !== "string") {
|
|
5367
|
+
return null;
|
|
5368
|
+
}
|
|
5369
|
+
switch (countryCode) {
|
|
5370
|
+
case "GB-ENG":
|
|
5371
|
+
case "GB-SCT":
|
|
5372
|
+
case "GB-WLS":
|
|
5373
|
+
return "UK";
|
|
5374
|
+
case "GB-NIR":
|
|
5375
|
+
return "XI";
|
|
5376
|
+
default:
|
|
5377
|
+
return countryCode;
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
get raw() {
|
|
5381
|
+
return this._raw;
|
|
5382
|
+
}
|
|
5383
|
+
isEartag() {
|
|
5384
|
+
return this._isEartag;
|
|
5385
|
+
}
|
|
5386
|
+
get isoCountryCode() {
|
|
5387
|
+
return this._isoCountryCode;
|
|
5388
|
+
}
|
|
5389
|
+
get nationalIdentifier() {
|
|
5390
|
+
return this._nationalIdentifier;
|
|
5391
|
+
}
|
|
5392
|
+
// private constructor
|
|
5393
|
+
constructor(input, fallbackCountryCode) {
|
|
5394
|
+
// readonly properties
|
|
5395
|
+
this._isEartag = false;
|
|
5396
|
+
fallbackCountryCode = this.normalisedCountryCode(fallbackCountryCode);
|
|
5397
|
+
let workingInput = input.replace(/\s/g, "").replace(/[^ -~]+/g, "");
|
|
5398
|
+
this._raw = workingInput; // Store the initial cleaned input. May get updated if prefix is added.
|
|
5399
|
+
// Part 1: Handle explicit country codes (alpha or numeric) in the input string
|
|
5400
|
+
let parsedCountryCode;
|
|
5401
|
+
let parsedNationalIdentifier;
|
|
5402
|
+
// 1a. Alpha prefix
|
|
5403
|
+
if (workingInput.length > 2 && /^[A-Z]{2}/.test(workingInput)) {
|
|
5404
|
+
const alphaCode = workingInput.slice(0, 2);
|
|
5405
|
+
const numericCode = EarTag.countryCodes[alphaCode];
|
|
5406
|
+
if (numericCode) {
|
|
5407
|
+
// Replace alpha with numeric for further parsing
|
|
5408
|
+
workingInput = numericCode + workingInput.slice(2);
|
|
5409
|
+
this._raw = workingInput; // Update _raw as it now contains numeric country code
|
|
5410
|
+
}
|
|
5411
|
+
// If unknown alpha, workingInput remains as is, will be handled by numeric check or fallback
|
|
5412
|
+
}
|
|
5413
|
+
// 1b. Numeric country code (already in workingInput, or converted from alpha)
|
|
5414
|
+
const countryPattern = "(372|826|899|528|250|276|056)";
|
|
5415
|
+
const regex12 = new RegExp(`^[0-9]{0,7}(${countryPattern})([0-9]{7})([0-9]{5})`);
|
|
5416
|
+
let match12 = regex12.exec(workingInput);
|
|
5417
|
+
if (match12) {
|
|
5418
|
+
parsedCountryCode = match12[1];
|
|
5419
|
+
parsedNationalIdentifier = `${match12[3]}${match12[4]}`;
|
|
5420
|
+
}
|
|
5421
|
+
else {
|
|
5422
|
+
const regex11 = new RegExp(`^[0-9]{0,7}(${countryPattern})([0-9]{6})([0-9]{5})`);
|
|
5423
|
+
let match11 = regex11.exec(workingInput);
|
|
5424
|
+
if (match11) {
|
|
5425
|
+
parsedCountryCode = match11[1];
|
|
5426
|
+
parsedNationalIdentifier = `${match11[3]}${match11[4]}`;
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
// Part 2: If no country code parsed yet, try fallback
|
|
5430
|
+
if (!parsedCountryCode && fallbackCountryCode) {
|
|
5431
|
+
const numericFallback = EarTag.countryCodes[fallbackCountryCode];
|
|
5432
|
+
if (numericFallback) {
|
|
5433
|
+
// `workingInput` at this point is the original input (cleaned, no recognized country code)
|
|
5434
|
+
// Assume `workingInput` is the national identifier part (must be 11 or 12 digits)
|
|
5435
|
+
if (workingInput.length === 12 || workingInput.length === 11) {
|
|
5436
|
+
parsedCountryCode = numericFallback;
|
|
5437
|
+
parsedNationalIdentifier = workingInput;
|
|
5438
|
+
// Update _raw to reflect the tag as if it had the country code
|
|
5439
|
+
this._raw = numericFallback + workingInput;
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
// Part 3: Finalize and set properties
|
|
5444
|
+
if (parsedCountryCode && parsedNationalIdentifier) {
|
|
5445
|
+
this._isoCountryCode = parsedCountryCode;
|
|
5446
|
+
if (parsedNationalIdentifier.length === 11) {
|
|
5447
|
+
// Pad 11-digit national ID to 12-digits by prepending "0"
|
|
5448
|
+
this._nationalIdentifier = "0" + parsedNationalIdentifier;
|
|
5449
|
+
}
|
|
5450
|
+
else if (parsedNationalIdentifier.length === 12) {
|
|
5451
|
+
this._nationalIdentifier = parsedNationalIdentifier;
|
|
5452
|
+
}
|
|
5453
|
+
else {
|
|
5454
|
+
// This case should ideally not be reached if lengths are checked properly before.
|
|
5455
|
+
this._isEartag = false;
|
|
5456
|
+
return;
|
|
5457
|
+
}
|
|
5458
|
+
this._isEartag = true;
|
|
5459
|
+
}
|
|
5460
|
+
else {
|
|
5461
|
+
this._isEartag = false;
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
static parse(str, fallbackCountryCode) {
|
|
5465
|
+
return new EarTag(str, fallbackCountryCode);
|
|
5466
|
+
}
|
|
5467
|
+
static format(str, marketCountry) {
|
|
5468
|
+
let t = EarTag.parse(str, marketCountry);
|
|
5469
|
+
if (t.isEartag()) {
|
|
5470
|
+
return t.toString();
|
|
5471
|
+
}
|
|
5472
|
+
return null;
|
|
5473
|
+
}
|
|
5474
|
+
toString() {
|
|
5475
|
+
if (!this._isEartag) {
|
|
5476
|
+
return "Invalid EarTag";
|
|
5477
|
+
}
|
|
5478
|
+
return `${EarTag.countryCodesByNumber[this.isoCountryCode]} ${this.nationalIdentifier.slice(0, 7)} ${this.nationalIdentifier.slice(7)}`;
|
|
5479
|
+
}
|
|
5480
|
+
isISO24631() {
|
|
5481
|
+
return EarTag.regexISO24631.test(this._raw);
|
|
5482
|
+
}
|
|
5483
|
+
toISO24631() {
|
|
5484
|
+
if (!this.isISO24631()) {
|
|
5485
|
+
return "Not a ISO24631 EarTag";
|
|
5486
|
+
}
|
|
5487
|
+
// ISO 24631 Formatting for movements
|
|
5488
|
+
const res = EarTag.regexISO24631.exec(this._raw);
|
|
5489
|
+
return `${res[1]} ${res[2]} ${res[3]} ${res[4]} ${res[5]} ${res[6]} ${res[7]} ${res[8]}`;
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
EarTag.regexISO24631 = /^([0-9]{1})([0-9]{1})([0-9]{2})([0-9]{2})([0-9]{1})(372|826|899|528|250|276)([0-9]{7})([0-9]{5})/;
|
|
5493
|
+
EarTag.countryCodes = {
|
|
5494
|
+
IE: "372",
|
|
5495
|
+
UK: "826",
|
|
5496
|
+
XI: "899",
|
|
5497
|
+
NL: "528",
|
|
5498
|
+
FR: "250",
|
|
5499
|
+
DE: "276",
|
|
5500
|
+
BE: "056",
|
|
5501
|
+
};
|
|
5502
|
+
|
|
5503
|
+
function lotComparator(a, b) {
|
|
5504
|
+
const aMatch = a.lotNumber.match(/^(\d+)(\D*)$/);
|
|
5505
|
+
const bMatch = b.lotNumber.match(/^(\d+)(\D*)$/);
|
|
5506
|
+
// If neither matches the pattern, fall back to string comparison
|
|
5507
|
+
if (!aMatch && !bMatch) {
|
|
5508
|
+
return a.lotNumber.localeCompare(b.lotNumber);
|
|
5509
|
+
}
|
|
5510
|
+
// If only one matches, the one with numbers comes after
|
|
5511
|
+
if (!aMatch)
|
|
5512
|
+
return -1;
|
|
5513
|
+
if (!bMatch)
|
|
5514
|
+
return 1;
|
|
5515
|
+
// Handle cases with numbers
|
|
5516
|
+
const aNum = parseInt(aMatch[1], 10);
|
|
5517
|
+
const bNum = parseInt(bMatch[1], 10);
|
|
5518
|
+
// Compare numeric parts first
|
|
5519
|
+
if (aNum !== bNum)
|
|
5520
|
+
return aNum - bNum;
|
|
5521
|
+
// Get alphabetic suffixes (or empty string if none)
|
|
5522
|
+
const aAlpha = (aMatch === null || aMatch === void 0 ? void 0 : aMatch[2]) || "";
|
|
5523
|
+
const bAlpha = (bMatch === null || bMatch === void 0 ? void 0 : bMatch[2]) || "";
|
|
5524
|
+
// Compare by length first (shorter comes first)
|
|
5525
|
+
if (aAlpha.length !== bAlpha.length)
|
|
5526
|
+
return aAlpha.length - bAlpha.length;
|
|
5527
|
+
// Then compare alphabetically
|
|
5528
|
+
return aAlpha.localeCompare(bAlpha);
|
|
5529
|
+
}
|
|
5530
|
+
function sortByLotNumber(lots) {
|
|
5531
|
+
return [...lots].sort(lotComparator);
|
|
5532
|
+
}
|
|
5533
|
+
/***
|
|
5534
|
+
* Generate the next lot number in a sequence:
|
|
5535
|
+
*/
|
|
5536
|
+
function nextLotNumber(previousLotNumber) {
|
|
5537
|
+
const match = previousLotNumber.match(/^(\d+)(\D*)$/);
|
|
5538
|
+
if (match) {
|
|
5539
|
+
// Has numeric part
|
|
5540
|
+
const numPart = parseInt(match[1], 10);
|
|
5541
|
+
const alphaPart = match[2];
|
|
5542
|
+
if (alphaPart === "") {
|
|
5543
|
+
// Just a number: 1 -> 2
|
|
5544
|
+
return (numPart + 1).toString();
|
|
5545
|
+
}
|
|
5546
|
+
else {
|
|
5547
|
+
// Alphanumeric: increment the alpha part
|
|
5548
|
+
const nextAlpha = incrementAlphaSequence(alphaPart);
|
|
5549
|
+
return numPart + nextAlpha;
|
|
5550
|
+
}
|
|
5551
|
+
}
|
|
5552
|
+
else {
|
|
5553
|
+
// Pure alphabetic: A -> B, Z -> AA, etc.
|
|
5554
|
+
return incrementAlphaSequence(previousLotNumber);
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
function incrementAlphaSequence(alpha) {
|
|
5558
|
+
if (alpha === "") {
|
|
5559
|
+
return "A";
|
|
5560
|
+
}
|
|
5561
|
+
// Convert to uppercase for consistent handling
|
|
5562
|
+
alpha = alpha.toUpperCase();
|
|
5563
|
+
// Check if we're at the end of sequence (all Z's)
|
|
5564
|
+
if (alpha === "Z".repeat(alpha.length)) {
|
|
5565
|
+
// Z -> AA, ZZ -> AAA, etc.
|
|
5566
|
+
return "A".repeat(alpha.length + 1);
|
|
5567
|
+
}
|
|
5568
|
+
// Convert string to array for easier manipulation
|
|
5569
|
+
let chars = alpha.split("");
|
|
5570
|
+
let carry = true;
|
|
5571
|
+
// Start from the rightmost character and work backwards
|
|
5572
|
+
for (let i = chars.length - 1; i >= 0 && carry; i--) {
|
|
5573
|
+
if (chars[i] === "Z") {
|
|
5574
|
+
chars[i] = "A";
|
|
5575
|
+
// carry remains true
|
|
5576
|
+
}
|
|
5577
|
+
else {
|
|
5578
|
+
// Increment the character
|
|
5579
|
+
chars[i] = String.fromCharCode(chars[i].charCodeAt(0) + 1);
|
|
5580
|
+
carry = false;
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
// If we still have carry, prepend an A
|
|
5584
|
+
if (carry) {
|
|
5585
|
+
chars.unshift("A");
|
|
5586
|
+
}
|
|
5587
|
+
return chars.join("");
|
|
5588
|
+
}
|
|
5589
|
+
|
|
5590
|
+
exports.EarTag = EarTag;
|
|
5219
5591
|
exports.Studio = Studio;
|
|
5220
5592
|
exports.StudioHeaders = StudioHeaders;
|
|
5221
5593
|
exports.StudioTypes = types;
|
|
5222
5594
|
exports.createAppManifest = createAppManifest;
|
|
5223
5595
|
exports.default = Studio;
|
|
5596
|
+
exports.lotComparator = lotComparator;
|
|
5597
|
+
exports.nextLotNumber = nextLotNumber;
|
|
5598
|
+
exports.sortByLotNumber = sortByLotNumber;
|
|
5224
5599
|
//# sourceMappingURL=index.js.map
|