tw-shift-schedule
Version:
118 lines (99 loc) • 3.7 kB
JavaScript
;
var moo = require('moo');
// Lexer: 利用 moo.lexer 對工作記錄進行切段,可以做出以下判斷:
// * 上班時間是否超過 12 小時?
// * 兩個上班時段間的休息時間,應該是休息時間,還是下班時間?
// * 上班後是否有至少 8 小時的休息?
//
// lexer 只負責檢查「單一工作時段是否合法」
// 多個工作時段之間的關係,例如:每週含加班工時上限 72 小時、變形工時的休假日數等,不在此檢查
// **note: 因為變形工時不會增加工作時數,單日工時上限也相同,因此 lexer 一定要通過才有可能是合法的變形工時
module.exports = function (scheduleData, opts) {
if (!opts) opts = {};
if (!opts.min_between_shift) opts.min_between_shift = 8;
var lexer = moo.compile({
fullRest: /\.{1440,}/,
work: /x+/,
rest: /\.+/,
invalid: moo.error
});
// 補上最後的 newline 方便 lexer 處理
if (!scheduleData.endsWith('\n')) {
scheduleData += '\n';
}
// remove comments
scheduleData = scheduleData.replace(/#.+\n/, '');
// ignore all spaces within the scheduleData
scheduleData = scheduleData.replace(/\s/g, '');
lexer.reset(scheduleData);
var tokens = [];
var token;
var minuteWorked = 0;
var workTokens = [];
while (token = lexer.next()) {
if (token.type === 'fullRest') {
// 休息了 24 小時那就一定是前一班結束了
pushWorkTokensIfNotEmpty();
tokens.push(token);
}
if (token.type === 'rest') {
// 34 條
/*
勞工工作採輪班制者,其工作班次,每週更換一次。但經勞工同意者不在此限。
依前項更換班次時,至少應有連續十一小時之休息時間。但因工作特性或
特殊原因,經中央目的事業主管機關商請中央主管機關公告者,得變更休
息時間不少於連續八小時。
*/
// TODO: 勞資協商前是 11 小時
// 遇到超過輪班間隔底限的休息時斷,就視為前一班已經結束。
// 因為把前後兩班視成一班對雇主完全沒好處,應不會有人這樣排。
if (token.value.length >= opts.min_between_shift * 60) {
pushWorkTokensIfNotEmpty();
tokens.push(token);
} else {
workTokens.push(token);
}
}
if (token.type === 'work') {
minuteWorked += token.value.length;
if (minuteWorked > 12 * 60) {
pushWorkTokensIfNotEmpty();
tokens.push({ type: 'invalid', value: token.value, offset: token.offset });
break;
}
workTokens.push(token);
}
}
pushWorkTokensIfNotEmpty();
return tokens;
function pushWorkTokensIfNotEmpty() {
minuteWorked = 0;
if (workTokens.length > 0) {
var combinedWorkToken = { type: 'work', value: '', offset: workTokens[0].offset };
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = workTokens[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var t = _step.value;
combinedWorkToken.value += t.value;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
tokens.push(combinedWorkToken);
workTokens = [];
}
}
};