perttool 0.1.0 → 0.3.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.
Files changed (213) hide show
  1. package/CHANGELOG.md +112 -33
  2. package/README.md +206 -111
  3. package/dist/analysis/temporal-deadline.d.ts +59 -0
  4. package/dist/analysis/temporal-deadline.d.ts.map +1 -0
  5. package/dist/analysis/temporal-deadline.js +387 -0
  6. package/dist/analysis/temporal-deadline.js.map +1 -0
  7. package/dist/analysis/temporal-precedence.d.ts +45 -0
  8. package/dist/analysis/temporal-precedence.d.ts.map +1 -0
  9. package/dist/analysis/temporal-precedence.js +123 -0
  10. package/dist/analysis/temporal-precedence.js.map +1 -0
  11. package/dist/analysis/temporal-resource.d.ts +66 -0
  12. package/dist/analysis/temporal-resource.d.ts.map +1 -0
  13. package/dist/analysis/temporal-resource.js +292 -0
  14. package/dist/analysis/temporal-resource.js.map +1 -0
  15. package/dist/application/analyze.js +5 -5
  16. package/dist/application/analyze.js.map +1 -1
  17. package/dist/application/check.d.ts +16 -0
  18. package/dist/application/check.d.ts.map +1 -1
  19. package/dist/application/check.js +51 -0
  20. package/dist/application/check.js.map +1 -1
  21. package/dist/application/contract4.d.ts +17 -0
  22. package/dist/application/contract4.d.ts.map +1 -0
  23. package/dist/application/contract4.js +27 -0
  24. package/dist/application/contract4.js.map +1 -0
  25. package/dist/application/init.d.ts +43 -0
  26. package/dist/application/init.d.ts.map +1 -0
  27. package/dist/application/init.js +226 -0
  28. package/dist/application/init.js.map +1 -0
  29. package/dist/application/mutate.d.ts +19 -0
  30. package/dist/application/mutate.d.ts.map +1 -1
  31. package/dist/application/mutate.js +47 -25
  32. package/dist/application/mutate.js.map +1 -1
  33. package/dist/application/next.d.ts +2 -0
  34. package/dist/application/next.d.ts.map +1 -1
  35. package/dist/application/next.js +7 -1
  36. package/dist/application/next.js.map +1 -1
  37. package/dist/application/project.d.ts +3 -1
  38. package/dist/application/project.d.ts.map +1 -1
  39. package/dist/application/project.js +2 -1
  40. package/dist/application/project.js.map +1 -1
  41. package/dist/application/target-check.d.ts +34 -0
  42. package/dist/application/target-check.d.ts.map +1 -0
  43. package/dist/application/target-check.js +90 -0
  44. package/dist/application/target-check.js.map +1 -0
  45. package/dist/application/target-grammar-boundary.d.ts +22 -0
  46. package/dist/application/target-grammar-boundary.d.ts.map +1 -0
  47. package/dist/application/target-grammar-boundary.js +91 -0
  48. package/dist/application/target-grammar-boundary.js.map +1 -0
  49. package/dist/application/target-mutate.d.ts +8 -0
  50. package/dist/application/target-mutate.d.ts.map +1 -0
  51. package/dist/application/target-mutate.js +56 -0
  52. package/dist/application/target-mutate.js.map +1 -0
  53. package/dist/application/target-project.d.ts +28 -0
  54. package/dist/application/target-project.d.ts.map +1 -0
  55. package/dist/application/target-project.js +60 -0
  56. package/dist/application/target-project.js.map +1 -0
  57. package/dist/application/target-temporal-analysis.d.ts +138 -0
  58. package/dist/application/target-temporal-analysis.d.ts.map +1 -0
  59. package/dist/application/target-temporal-analysis.js +409 -0
  60. package/dist/application/target-temporal-analysis.js.map +1 -0
  61. package/dist/application/target-temporal-input.d.ts +86 -0
  62. package/dist/application/target-temporal-input.d.ts.map +1 -0
  63. package/dist/application/target-temporal-input.js +238 -0
  64. package/dist/application/target-temporal-input.js.map +1 -0
  65. package/dist/application/target-unit-migration-candidate.d.ts +60 -0
  66. package/dist/application/target-unit-migration-candidate.d.ts.map +1 -0
  67. package/dist/application/target-unit-migration-candidate.js +290 -0
  68. package/dist/application/target-unit-migration-candidate.js.map +1 -0
  69. package/dist/application/target-unit-migration-request.d.ts +35 -0
  70. package/dist/application/target-unit-migration-request.d.ts.map +1 -0
  71. package/dist/application/target-unit-migration-request.js +68 -0
  72. package/dist/application/target-unit-migration-request.js.map +1 -0
  73. package/dist/application/target-unit-migration-result.d.ts +66 -0
  74. package/dist/application/target-unit-migration-result.d.ts.map +1 -0
  75. package/dist/application/target-unit-migration-result.js +86 -0
  76. package/dist/application/target-unit-migration-result.js.map +1 -0
  77. package/dist/application/unit-migration.d.ts +13 -0
  78. package/dist/application/unit-migration.d.ts.map +1 -0
  79. package/dist/application/unit-migration.js +9 -0
  80. package/dist/application/unit-migration.js.map +1 -0
  81. package/dist/cli.js +494 -383
  82. package/dist/cli.js.map +1 -1
  83. package/dist/command/discovery.d.ts +30 -0
  84. package/dist/command/discovery.d.ts.map +1 -0
  85. package/dist/command/discovery.js +752 -0
  86. package/dist/command/discovery.js.map +1 -0
  87. package/dist/command/registry.d.ts +84 -0
  88. package/dist/command/registry.d.ts.map +1 -0
  89. package/dist/command/registry.js +964 -0
  90. package/dist/command/registry.js.map +1 -0
  91. package/dist/command/usage.d.ts +42 -0
  92. package/dist/command/usage.d.ts.map +1 -0
  93. package/dist/command/usage.js +337 -0
  94. package/dist/command/usage.js.map +1 -0
  95. package/dist/conversion/mermaid-import.js +56 -56
  96. package/dist/conversion/mermaid-import.js.map +1 -1
  97. package/dist/conversion/mermaid.js +1 -1
  98. package/dist/conversion/mermaid.js.map +1 -1
  99. package/dist/formatter/source-formatter.d.ts +12 -0
  100. package/dist/formatter/source-formatter.d.ts.map +1 -1
  101. package/dist/formatter/source-formatter.js +48 -6
  102. package/dist/formatter/source-formatter.js.map +1 -1
  103. package/dist/formatter/target-source-formatter.d.ts +8 -0
  104. package/dist/formatter/target-source-formatter.d.ts.map +1 -0
  105. package/dist/formatter/target-source-formatter.js +36 -0
  106. package/dist/formatter/target-source-formatter.js.map +1 -0
  107. package/dist/help/guide.d.ts +12 -0
  108. package/dist/help/guide.d.ts.map +1 -0
  109. package/dist/help/guide.js +103 -0
  110. package/dist/help/guide.js.map +1 -0
  111. package/dist/help/registry.d.ts +0 -6
  112. package/dist/help/registry.d.ts.map +1 -1
  113. package/dist/help/registry.js +186 -86
  114. package/dist/help/registry.js.map +1 -1
  115. package/dist/index.d.ts +20 -7
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +8 -3
  118. package/dist/index.js.map +1 -1
  119. package/dist/io/safe-write.d.ts +7 -0
  120. package/dist/io/safe-write.d.ts.map +1 -1
  121. package/dist/io/safe-write.js +36 -27
  122. package/dist/io/safe-write.js.map +1 -1
  123. package/dist/io/target-safe-write.d.ts +7 -0
  124. package/dist/io/target-safe-write.d.ts.map +1 -0
  125. package/dist/io/target-safe-write.js +33 -0
  126. package/dist/io/target-safe-write.js.map +1 -0
  127. package/dist/migration/conversion.d.ts +40 -0
  128. package/dist/migration/conversion.d.ts.map +1 -0
  129. package/dist/migration/conversion.js +106 -0
  130. package/dist/migration/conversion.js.map +1 -0
  131. package/dist/migration/grammar-boundary.d.ts +20 -0
  132. package/dist/migration/grammar-boundary.d.ts.map +1 -0
  133. package/dist/migration/grammar-boundary.js +92 -0
  134. package/dist/migration/grammar-boundary.js.map +1 -0
  135. package/dist/migration/request.d.ts +79 -0
  136. package/dist/migration/request.d.ts.map +1 -0
  137. package/dist/migration/request.js +308 -0
  138. package/dist/migration/request.js.map +1 -0
  139. package/dist/model/calendar-arithmetic.d.ts +46 -0
  140. package/dist/model/calendar-arithmetic.d.ts.map +1 -0
  141. package/dist/model/calendar-arithmetic.js +236 -0
  142. package/dist/model/calendar-arithmetic.js.map +1 -0
  143. package/dist/model/calendar.d.ts +22 -0
  144. package/dist/model/calendar.d.ts.map +1 -0
  145. package/dist/model/calendar.js +83 -0
  146. package/dist/model/calendar.js.map +1 -0
  147. package/dist/model/declaration-fields.d.ts +15 -0
  148. package/dist/model/declaration-fields.d.ts.map +1 -0
  149. package/dist/model/declaration-fields.js +54 -0
  150. package/dist/model/declaration-fields.js.map +1 -0
  151. package/dist/model/exact-duration-source.d.ts +10 -0
  152. package/dist/model/exact-duration-source.d.ts.map +1 -0
  153. package/dist/model/exact-duration-source.js +69 -0
  154. package/dist/model/exact-duration-source.js.map +1 -0
  155. package/dist/model/rational.d.ts +2 -2
  156. package/dist/model/rational.d.ts.map +1 -1
  157. package/dist/model/rational.js +3 -1
  158. package/dist/model/rational.js.map +1 -1
  159. package/dist/model/syntax.d.ts +9 -2
  160. package/dist/model/syntax.d.ts.map +1 -1
  161. package/dist/model/syntax.js +20 -4
  162. package/dist/model/syntax.js.map +1 -1
  163. package/dist/model/target-calendar.d.ts +25 -0
  164. package/dist/model/target-calendar.d.ts.map +1 -0
  165. package/dist/model/target-calendar.js +56 -0
  166. package/dist/model/target-calendar.js.map +1 -0
  167. package/dist/mutation/advance.d.ts.map +1 -1
  168. package/dist/mutation/advance.js +21 -4
  169. package/dist/mutation/advance.js.map +1 -1
  170. package/dist/mutation/gate.d.ts +5 -0
  171. package/dist/mutation/gate.d.ts.map +1 -0
  172. package/dist/mutation/gate.js +156 -0
  173. package/dist/mutation/gate.js.map +1 -0
  174. package/dist/mutation/milestone.d.ts +10 -1
  175. package/dist/mutation/milestone.d.ts.map +1 -1
  176. package/dist/mutation/milestone.js +104 -48
  177. package/dist/mutation/milestone.js.map +1 -1
  178. package/dist/mutation/project.d.ts +7 -1
  179. package/dist/mutation/project.d.ts.map +1 -1
  180. package/dist/mutation/project.js +32 -19
  181. package/dist/mutation/project.js.map +1 -1
  182. package/dist/mutation/resource.js +22 -22
  183. package/dist/mutation/resource.js.map +1 -1
  184. package/dist/mutation/target-types.d.ts +42 -0
  185. package/dist/mutation/target-types.d.ts.map +1 -0
  186. package/dist/mutation/target-types.js +2 -0
  187. package/dist/mutation/target-types.js.map +1 -0
  188. package/dist/mutation/task.d.ts +12 -1
  189. package/dist/mutation/task.d.ts.map +1 -1
  190. package/dist/mutation/task.js +148 -89
  191. package/dist/mutation/task.js.map +1 -1
  192. package/dist/mutation/types.d.ts +34 -3
  193. package/dist/mutation/types.d.ts.map +1 -1
  194. package/dist/parser/document-parser.d.ts +14 -0
  195. package/dist/parser/document-parser.d.ts.map +1 -1
  196. package/dist/parser/document-parser.js +159 -55
  197. package/dist/parser/document-parser.js.map +1 -1
  198. package/dist/recommendation/override-types.d.ts +2 -2
  199. package/dist/recommendation/override.d.ts +2 -2
  200. package/dist/recommendation/override.d.ts.map +1 -1
  201. package/dist/recommendation/override.js +49 -12
  202. package/dist/recommendation/override.js.map +1 -1
  203. package/dist/semantic/target-validator.d.ts +36 -0
  204. package/dist/semantic/target-validator.d.ts.map +1 -0
  205. package/dist/semantic/target-validator.js +87 -0
  206. package/dist/semantic/target-validator.js.map +1 -0
  207. package/dist/semantic/validator.d.ts +2 -0
  208. package/dist/semantic/validator.d.ts.map +1 -1
  209. package/dist/semantic/validator.js +90 -45
  210. package/dist/semantic/validator.js.map +1 -1
  211. package/dist/version.d.ts +1 -1
  212. package/dist/version.js +1 -1
  213. package/package.json +3 -3
@@ -1,23 +1,25 @@
1
1
  import { fieldNamed } from "../model/syntax.js";
2
+ import { GRAMMAR_1_DECLARATION_FIELD_ORDER, TARGET_GRAMMAR_2_DECLARATION_FIELD_ORDER, } from "../model/declaration-fields.js";
3
+ import { canonicalizeExactDurationSourceToken, } from "../model/exact-duration-source.js";
2
4
  import { mutationDiagnostic } from "./diagnostics.js";
3
5
  import { appendDeclarationEdit, contentEndOffset, contentTextEndOffset, deleteDeclarationEdit, deleteFieldEdit, fieldInsertionOffset, insertionText, leadingCommentStart, lineIndexAt, majorLineEnding, serializeTags, serializeTextField, splitPhysicalLines, } from "./source.js";
4
- const fieldOrder = [
5
- "title",
6
- "description",
7
- "duration",
8
- "estimate",
9
- "status",
10
- "priority",
11
- "requires",
12
- "owner",
13
- "tags",
14
- "blocked_reason",
15
- "source",
16
- ];
17
- const fieldRank = new Map(fieldOrder.map((name, index) => [name, name === "estimate" ? 2 : index]));
18
- fieldRank.set("duration", 2);
6
+ export const ACTIVE_TASK_MUTATION_PROFILE = Object.freeze({
7
+ fieldOrder: GRAMMAR_1_DECLARATION_FIELD_ORDER.task,
8
+ temporalFields: false,
9
+ exactDurations: false,
10
+ });
11
+ export const TARGET_GRAMMAR_2_TASK_MUTATION_PROFILE = Object.freeze({
12
+ fieldOrder: TARGET_GRAMMAR_2_DECLARATION_FIELD_ORDER.task,
13
+ temporalFields: true,
14
+ exactDurations: false,
15
+ });
16
+ export const TARGET_GRAMMAR_3_TASK_MUTATION_PROFILE = Object.freeze({
17
+ fieldOrder: TARGET_GRAMMAR_2_DECLARATION_FIELD_ORDER.task,
18
+ temporalFields: true,
19
+ exactDurations: true,
20
+ });
19
21
  const taskStatuses = new Set(["planned", "active", "blocked", "done"]);
20
- const clearableFields = new Set([
22
+ const activeClearableFields = [
21
23
  "description",
22
24
  "status",
23
25
  "priority",
@@ -26,7 +28,10 @@ const clearableFields = new Set([
26
28
  "source",
27
29
  "tags",
28
30
  "requires",
29
- ]);
31
+ ];
32
+ function fieldRank(profile) {
33
+ return new Map(profile.fieldOrder.map((name, index) => [name, index]));
34
+ }
30
35
  function validEstimate(value) {
31
36
  if (value === null || typeof value !== "object")
32
37
  return false;
@@ -45,15 +50,16 @@ function validRequirement(value) {
45
50
  function validStringArray(value) {
46
51
  return Array.isArray(value) && value.every((item) => typeof item === "string");
47
52
  }
48
- function taskDefinitionError(value) {
53
+ function taskDefinitionError(value, profile) {
49
54
  if (value === null || typeof value !== "object")
50
- return "task definitionがobjectではありません";
55
+ return "task definition is not an object";
51
56
  const task = value;
52
57
  const knownFields = new Set([
53
58
  "title",
54
59
  "description",
55
60
  "duration",
56
61
  "estimate",
62
+ ...(profile.temporalFields ? ["notBefore", "deadline"] : []),
57
63
  "status",
58
64
  "priority",
59
65
  "requirements",
@@ -63,42 +69,48 @@ function taskDefinitionError(value) {
63
69
  "source",
64
70
  ]);
65
71
  if (Object.keys(task).some((name) => !knownFields.has(name))) {
66
- return "task definitionに未対応fieldが含まれています";
72
+ return "task definition contains unsupported fields";
67
73
  }
68
74
  if (typeof task["title"] !== "string")
69
- return "task titleがstringではありません";
75
+ return "task title is not a string";
70
76
  if ((task["duration"] === undefined) === (task["estimate"] === undefined)) {
71
- return "durationまたはestimateのexactly oneを必要とします";
77
+ return "exactly one of duration or estimate is required";
72
78
  }
73
79
  if (task["duration"] !== undefined && typeof task["duration"] !== "string") {
74
- return "durationがstringではありません";
80
+ return "duration is not a string";
75
81
  }
76
82
  if (task["estimate"] !== undefined && !validEstimate(task["estimate"])) {
77
- return "estimateはoptimistic、mostLikely、pessimisticのstringを必要とします";
83
+ return "estimate requires optimistic, mostLikely, and pessimistic string fields";
78
84
  }
79
- for (const name of ["description", "owner", "blockedReason", "source"]) {
85
+ for (const name of [
86
+ "description",
87
+ "owner",
88
+ "blockedReason",
89
+ "source",
90
+ ...(profile.temporalFields ? ["notBefore", "deadline"] : []),
91
+ ]) {
80
92
  if (task[name] !== undefined && typeof task[name] !== "string") {
81
- return `${name}がstringではありません`;
93
+ return `${name} is not a string`;
82
94
  }
83
95
  }
84
96
  if (task["status"] !== undefined && !taskStatuses.has(task["status"])) {
85
- return "statusがtask statusではありません";
97
+ return "status is not a task status";
86
98
  }
87
99
  if (task["priority"] !== undefined && !Number.isSafeInteger(task["priority"])) {
88
- return "priorityがsafe integerではありません";
100
+ return "priority is not a safe integer";
89
101
  }
90
102
  if (task["tags"] !== undefined && !validStringArray(task["tags"])) {
91
- return "tagsがstring arrayではありません";
103
+ return "tags are not a string array";
92
104
  }
93
105
  if (task["requirements"] !== undefined &&
94
106
  (!Array.isArray(task["requirements"]) || !task["requirements"].every(validRequirement))) {
95
- return "requirementsがresourceIdとsafe integer unitsのarrayではありません";
107
+ return "requirements must be an array of entries with resourceId and safe integer units";
96
108
  }
97
109
  return undefined;
98
110
  }
99
111
  function taskMutationRequestError(value) {
100
112
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
101
- return "mutation requestがobjectではありません";
113
+ return "mutation request is not an object";
102
114
  }
103
115
  const request = value;
104
116
  const kind = request["kind"];
@@ -106,10 +118,10 @@ function taskMutationRequestError(value) {
106
118
  kind !== "task.set" &&
107
119
  kind !== "task.remove" &&
108
120
  kind !== "task.finish") {
109
- return "mutation kindが未対応です";
121
+ return "mutation kind is unsupported";
110
122
  }
111
123
  if (typeof request["id"] !== "string")
112
- return "mutation idがstringではありません";
124
+ return "mutation id is not a string";
113
125
  const fieldsByKind = {
114
126
  "task.add": new Set(["kind", "id", "from", "to", "task"]),
115
127
  "task.set": new Set([
@@ -128,11 +140,14 @@ function taskMutationRequestError(value) {
128
140
  "task.finish": new Set(["kind", "id"]),
129
141
  };
130
142
  if (Object.keys(request).some((name) => !fieldsByKind[kind].has(name))) {
131
- return `${kind} requestに未対応fieldが含まれています`;
143
+ return `${kind} request contains unsupported fields`;
132
144
  }
133
145
  return undefined;
134
146
  }
135
- function canonicalDuration(value) {
147
+ function canonicalDuration(value, profile) {
148
+ if (profile.exactDurations) {
149
+ return canonicalizeExactDurationSourceToken(value)?.token ?? value;
150
+ }
136
151
  const match = /^(\d+)(?:\.(\d+))?([dhp])$/.exec(value);
137
152
  if (match === null)
138
153
  return value;
@@ -140,12 +155,12 @@ function canonicalDuration(value) {
140
155
  const fraction = (match[2] ?? "").replace(/0+$/, "");
141
156
  return `${whole}${fraction === "" ? "" : `.${fraction}`}${match[3]}`;
142
157
  }
143
- function serializeEstimate(estimate, lineEnding) {
158
+ function serializeEstimate(estimate, lineEnding, profile) {
144
159
  return [
145
160
  " estimate:",
146
- ` optimistic ${canonicalDuration(estimate.optimistic)}`,
147
- ` most_likely ${canonicalDuration(estimate.mostLikely)}`,
148
- ` pessimistic ${canonicalDuration(estimate.pessimistic)}`,
161
+ ` optimistic ${canonicalDuration(estimate.optimistic, profile)}`,
162
+ ` most_likely ${canonicalDuration(estimate.mostLikely, profile)}`,
163
+ ` pessimistic ${canonicalDuration(estimate.pessimistic, profile)}`,
149
164
  ].join(lineEnding);
150
165
  }
151
166
  function serializeRequirements(requirements, lineEnding) {
@@ -154,7 +169,7 @@ function serializeRequirements(requirements, lineEnding) {
154
169
  ...requirements.map(({ resourceId, units }) => ` ${resourceId} ${units}`),
155
170
  ].join(lineEnding);
156
171
  }
157
- function serializeField(name, value, lineEnding) {
172
+ function serializeField(name, value, lineEnding, profile) {
158
173
  switch (name) {
159
174
  case "title":
160
175
  case "owner":
@@ -164,9 +179,12 @@ function serializeField(name, value, lineEnding) {
164
179
  case "blocked_reason":
165
180
  return serializeTextField(name, value, lineEnding);
166
181
  case "duration":
167
- return ` duration ${canonicalDuration(value)}`;
182
+ return ` duration ${canonicalDuration(value, profile)}`;
168
183
  case "estimate":
169
- return serializeEstimate(value, lineEnding);
184
+ return serializeEstimate(value, lineEnding, profile);
185
+ case "not_before":
186
+ case "deadline":
187
+ return ` ${name} ${value}`;
170
188
  case "status":
171
189
  case "priority":
172
190
  return ` ${name} ${value}`;
@@ -186,6 +204,12 @@ function taskFields(task) {
186
204
  fields.set("duration", task.duration);
187
205
  if (task.estimate !== undefined)
188
206
  fields.set("estimate", task.estimate);
207
+ if ("notBefore" in task && task.notBefore !== undefined) {
208
+ fields.set("not_before", task.notBefore);
209
+ }
210
+ if ("deadline" in task && task.deadline !== undefined) {
211
+ fields.set("deadline", task.deadline);
212
+ }
189
213
  if (task.status !== undefined)
190
214
  fields.set("status", task.status);
191
215
  if (task.priority !== undefined)
@@ -202,37 +226,44 @@ function taskFields(task) {
202
226
  fields.set("source", task.source);
203
227
  return fields;
204
228
  }
205
- function serializeTask(mutation, lineEnding) {
229
+ function serializeTask(mutation, lineEnding, profile) {
230
+ if (mutation.kind !== "task.add") {
231
+ throw new Error("task serializer requires task.add");
232
+ }
206
233
  const fields = taskFields(mutation.task);
207
234
  return [
208
235
  `task ${mutation.id} ${mutation.from} -> ${mutation.to}:`,
209
- ...fieldOrder.flatMap((name) => {
236
+ ...profile.fieldOrder.flatMap((name) => {
210
237
  if (name === "duration" && fields.has("estimate"))
211
238
  return [];
212
239
  if (name === "estimate" && fields.has("duration"))
213
240
  return [];
214
- return fields.has(name) ? [serializeField(name, fields.get(name), lineEnding)] : [];
241
+ return fields.has(name)
242
+ ? [serializeField(name, fields.get(name), lineEnding, profile)]
243
+ : [];
215
244
  }),
216
245
  ].join(lineEnding);
217
246
  }
218
- function addTaskPlan(text, mutation) {
247
+ function addTaskPlan(text, mutation, profile) {
219
248
  const task = mutation.task;
220
- const taskError = taskDefinitionError(task);
249
+ const taskError = taskDefinitionError(task, profile);
221
250
  if (typeof mutation.id !== "string" ||
222
251
  typeof mutation.from !== "string" ||
223
252
  typeof mutation.to !== "string" ||
224
253
  taskError !== undefined) {
225
254
  return {
226
255
  edits: [],
227
- diagnostic: mutationDiagnostic("PTMUT-301", `task.add requestが不正です${taskError === undefined ? "" : `: ${taskError}`}`),
256
+ diagnostic: mutationDiagnostic("PTMUT-301", `task.add request is invalid${taskError === undefined ? "" : `: ${taskError}`}`),
228
257
  };
229
258
  }
230
259
  const lineEnding = majorLineEnding(text);
231
260
  return {
232
- edits: [appendDeclarationEdit(text, serializeTask(mutation, lineEnding), lineEnding)],
261
+ edits: [
262
+ appendDeclarationEdit(text, serializeTask(mutation, lineEnding, profile), lineEnding),
263
+ ],
233
264
  };
234
265
  }
235
- function setRequestError(mutation) {
266
+ function setRequestError(mutation, profile) {
236
267
  const rawSet = mutation.set;
237
268
  const rawClear = mutation.clear;
238
269
  const rawAddTags = mutation.addTags;
@@ -241,7 +272,7 @@ function setRequestError(mutation) {
241
272
  const rawRemoveRequirements = mutation.removeRequirements;
242
273
  if (rawSet !== undefined &&
243
274
  (rawSet === null || typeof rawSet !== "object" || Array.isArray(rawSet))) {
244
- return "setがobjectではありません";
275
+ return "set is not an object";
245
276
  }
246
277
  for (const [name, value] of [
247
278
  ["clear", rawClear],
@@ -251,7 +282,7 @@ function setRequestError(mutation) {
251
282
  ["removeRequirements", rawRemoveRequirements],
252
283
  ]) {
253
284
  if (value !== undefined && !Array.isArray(value))
254
- return `${name}がarrayではありません`;
285
+ return `${name} is not an array`;
255
286
  }
256
287
  const set = (rawSet ?? {});
257
288
  const setEntries = Object.entries(set).filter(([, value]) => value !== undefined);
@@ -268,22 +299,23 @@ function setRequestError(mutation) {
268
299
  removeTags.length === 0 &&
269
300
  upsertRequirements.length === 0 &&
270
301
  removeRequirements.length === 0) {
271
- return "task.setは少なくとも1つの変更指定を必要とします";
302
+ return "task.set requires at least one change specification";
272
303
  }
273
304
  if (set.duration !== undefined && set.estimate !== undefined) {
274
- return "durationとestimateは同時にsetできません";
305
+ return "duration and estimate cannot both be specified in set";
275
306
  }
276
307
  if (mutation.from !== undefined && typeof mutation.from !== "string") {
277
- return "fromがstringではありません";
308
+ return "from is not a string";
278
309
  }
279
310
  if (mutation.to !== undefined && typeof mutation.to !== "string") {
280
- return "toがstringではありません";
311
+ return "to is not a string";
281
312
  }
282
313
  const knownSetFields = new Set([
283
314
  "title",
284
315
  "description",
285
316
  "duration",
286
317
  "estimate",
318
+ ...(profile.temporalFields ? ["notBefore", "deadline"] : []),
287
319
  "status",
288
320
  "priority",
289
321
  "owner",
@@ -291,41 +323,57 @@ function setRequestError(mutation) {
291
323
  "source",
292
324
  ]);
293
325
  if (Object.keys(set).some((name) => !knownSetFields.has(name))) {
294
- return "setに未対応fieldが含まれています";
326
+ return "set contains unsupported fields";
295
327
  }
296
- for (const name of ["title", "description", "duration", "owner", "blockedReason", "source"]) {
297
- if (set[name] !== undefined && typeof set[name] !== "string") {
298
- return `${name}がstringではありません`;
328
+ for (const name of [
329
+ "title",
330
+ "description",
331
+ "duration",
332
+ "owner",
333
+ "blockedReason",
334
+ "source",
335
+ ...(profile.temporalFields ? ["notBefore", "deadline"] : []),
336
+ ]) {
337
+ if (set[name] !== undefined &&
338
+ typeof set[name] !== "string") {
339
+ return `${name} is not a string`;
299
340
  }
300
341
  }
301
342
  if (set.estimate !== undefined && !validEstimate(set.estimate)) {
302
- return "estimateはoptimistic、mostLikely、pessimisticのstringを必要とします";
343
+ return "estimate requires optimistic, mostLikely, and pessimistic string fields";
303
344
  }
304
345
  if (set.status !== undefined && !taskStatuses.has(set.status)) {
305
- return "statusがtask statusではありません";
346
+ return "status is not a task status";
306
347
  }
307
348
  if (set.priority !== undefined && !Number.isSafeInteger(set.priority)) {
308
- return "priorityがsafe integerではありません";
349
+ return "priority is not a safe integer";
309
350
  }
351
+ const clearableFields = new Set([
352
+ ...activeClearableFields,
353
+ ...(profile.temporalFields ? ["not_before", "deadline"] : []),
354
+ ]);
310
355
  if (!Array.isArray(clear) || clear.some((name) => !clearableFields.has(name))) {
311
- return "clearに未対応fieldが含まれています";
356
+ return "clear contains unsupported fields";
312
357
  }
313
358
  if (!validStringArray(addTags) || !validStringArray(removeTags)) {
314
- return "addTagsとremoveTagsはstring arrayである必要があります";
359
+ return "addTags and removeTags must be string arrays";
315
360
  }
316
361
  if (!Array.isArray(upsertRequirements) ||
317
362
  !upsertRequirements.every(validRequirement) ||
318
363
  !validStringArray(removeRequirements)) {
319
- return "requirement変更指定が不正です";
364
+ return "requirement change specification is invalid";
320
365
  }
321
366
  if (new Set(clear).size !== clear.length)
322
- return "clear fieldが重複しています";
367
+ return "clear contains duplicate fields";
323
368
  const clearNames = new Set(clear);
324
369
  const setToClear = {
325
370
  title: "title",
326
371
  description: "description",
327
372
  duration: "duration",
328
373
  estimate: "estimate",
374
+ ...(profile.temporalFields
375
+ ? { notBefore: "not_before", deadline: "deadline" }
376
+ : {}),
329
377
  status: "status",
330
378
  priority: "priority",
331
379
  owner: "owner",
@@ -334,27 +382,27 @@ function setRequestError(mutation) {
334
382
  };
335
383
  for (const [name] of setEntries) {
336
384
  if (clearNames.has(setToClear[name])) {
337
- return `${setToClear[name]}をsetとclearへ同時指定できません`;
385
+ return `${setToClear[name]} cannot be specified in both set and clear`;
338
386
  }
339
387
  }
340
388
  if (clearNames.has("tags") && (addTags.length > 0 || removeTags.length > 0)) {
341
- return "clear tagsとadd/remove tagは併用できません";
389
+ return "clear tags cannot be combined with add/remove tags";
342
390
  }
343
391
  if (clearNames.has("requires") &&
344
392
  (upsertRequirements.length > 0 || removeRequirements.length > 0)) {
345
- return "clear requiresとupsert/remove requirementは併用できません";
393
+ return "clear requires cannot be combined with upsert/remove requirements";
346
394
  }
347
395
  const removedTags = new Set(removeTags);
348
396
  if (addTags.some((tag) => removedTags.has(tag))) {
349
- return "同じtagをaddとremoveへ同時指定できません";
397
+ return "the same tag cannot be specified in both add and remove";
350
398
  }
351
399
  const removedResources = new Set(removeRequirements);
352
400
  if (upsertRequirements.some(({ resourceId }) => removedResources.has(resourceId))) {
353
- return "同じresourceをupsertとremoveへ同時指定できません";
401
+ return "the same resource cannot be specified in both upsert and remove";
354
402
  }
355
403
  const upsertIds = upsertRequirements.map(({ resourceId }) => resourceId);
356
404
  if (new Set(upsertIds).size !== upsertIds.length) {
357
- return "upsert requirementのresourceが重複しています";
405
+ return "upsert requirements contain duplicate resources";
358
406
  }
359
407
  return undefined;
360
408
  }
@@ -370,8 +418,8 @@ function currentRequirements(task) {
370
418
  ? value.map(({ resourceId, units }) => ({ resourceId, units }))
371
419
  : [];
372
420
  }
373
- function planSetTask(text, task, mutation) {
374
- const error = setRequestError(mutation);
421
+ function planSetTask(text, task, mutation, profile) {
422
+ const error = setRequestError(mutation, profile);
375
423
  if (error !== undefined) {
376
424
  return { edits: [], diagnostic: mutationDiagnostic("PTMUT-301", error, task) };
377
425
  }
@@ -380,10 +428,14 @@ function planSetTask(text, task, mutation) {
380
428
  const edits = [];
381
429
  const deleted = new Set(mutation.clear ?? []);
382
430
  const additions = new Map();
431
+ const rank = fieldRank(profile);
383
432
  const queueAddition = (name, value) => {
384
- const offset = fieldInsertionOffset(task, name, deleted, lines, fieldRank);
433
+ const offset = fieldInsertionOffset(task, name, deleted, lines, rank);
385
434
  const entries = additions.get(offset) ?? [];
386
- entries.push({ name, serialized: serializeField(name, value, lineEnding) });
435
+ entries.push({
436
+ name,
437
+ serialized: serializeField(name, value, lineEnding, profile),
438
+ });
387
439
  additions.set(offset, entries);
388
440
  };
389
441
  const setScalar = (name, value, valueText) => {
@@ -432,6 +484,7 @@ function planSetTask(text, task, mutation) {
432
484
  });
433
485
  }
434
486
  const set = mutation.set ?? {};
487
+ const targetSet = set;
435
488
  if (set.title !== undefined)
436
489
  setScalar("title", set.title, JSON.stringify(set.title));
437
490
  if (set.description !== undefined)
@@ -440,13 +493,13 @@ function planSetTask(text, task, mutation) {
440
493
  const duration = fieldNamed(task, "duration");
441
494
  const estimate = fieldNamed(task, "estimate");
442
495
  if (duration !== undefined) {
443
- setScalar("duration", set.duration, canonicalDuration(set.duration));
496
+ setScalar("duration", set.duration, canonicalDuration(set.duration, profile));
444
497
  }
445
498
  else if (estimate !== undefined) {
446
499
  edits.push({
447
500
  startOffset: estimate.span.start.offset,
448
501
  endOffset: contentTextEndOffset(estimate, lines),
449
- replacement: serializeField("duration", set.duration, lineEnding),
502
+ replacement: serializeField("duration", set.duration, lineEnding, profile),
450
503
  });
451
504
  }
452
505
  }
@@ -463,7 +516,7 @@ function planSetTask(text, task, mutation) {
463
516
  edits.push({
464
517
  startOffset: child.valueSpan.start.offset,
465
518
  endOffset: child.valueSpan.end.offset,
466
- replacement: canonicalDuration(value),
519
+ replacement: canonicalDuration(value, profile),
467
520
  });
468
521
  }
469
522
  }
@@ -471,10 +524,16 @@ function planSetTask(text, task, mutation) {
471
524
  edits.push({
472
525
  startOffset: duration.span.start.offset,
473
526
  endOffset: contentTextEndOffset(duration, lines),
474
- replacement: serializeEstimate(set.estimate, lineEnding),
527
+ replacement: serializeEstimate(set.estimate, lineEnding, profile),
475
528
  });
476
529
  }
477
530
  }
531
+ if (profile.temporalFields && targetSet.notBefore !== undefined) {
532
+ setScalar("not_before", targetSet.notBefore, targetSet.notBefore);
533
+ }
534
+ if (profile.temporalFields && targetSet.deadline !== undefined) {
535
+ setScalar("deadline", targetSet.deadline, targetSet.deadline);
536
+ }
478
537
  if (set.status !== undefined)
479
538
  setScalar("status", set.status, set.status);
480
539
  if (set.priority !== undefined)
@@ -586,7 +645,7 @@ function planSetTask(text, task, mutation) {
586
645
  edits.push(deleteFieldEdit(field, lines));
587
646
  }
588
647
  for (const [offset, entries] of additions) {
589
- entries.sort((left, right) => (fieldRank.get(left.name) ?? 99) - (fieldRank.get(right.name) ?? 99));
648
+ entries.sort((left, right) => (rank.get(left.name) ?? 99) - (rank.get(right.name) ?? 99));
590
649
  edits.push({
591
650
  startOffset: offset,
592
651
  endOffset: offset,
@@ -595,7 +654,7 @@ function planSetTask(text, task, mutation) {
595
654
  }
596
655
  return { edits };
597
656
  }
598
- export function planTaskMutationEdits(text, document, mutation) {
657
+ export function planTaskMutationEdits(text, document, mutation, profile = ACTIVE_TASK_MUTATION_PROFILE) {
599
658
  const requestError = taskMutationRequestError(mutation);
600
659
  if (requestError !== undefined) {
601
660
  return {
@@ -608,21 +667,21 @@ export function planTaskMutationEdits(text, document, mutation) {
608
667
  if (entity !== undefined) {
609
668
  return {
610
669
  edits: [],
611
- diagnostic: mutationDiagnostic("PTMUT-304", `entity ID ${mutation.id}はすでに使用されています`, entity),
670
+ diagnostic: mutationDiagnostic("PTMUT-304", `entity ID ${mutation.id} is already in use`, entity),
612
671
  };
613
672
  }
614
- return addTaskPlan(text, mutation);
673
+ return addTaskPlan(text, mutation, profile);
615
674
  }
616
675
  if (entity === undefined) {
617
676
  return {
618
677
  edits: [],
619
- diagnostic: mutationDiagnostic("PTMUT-302", `task ${mutation.id}が存在しません`),
678
+ diagnostic: mutationDiagnostic("PTMUT-302", `task ${mutation.id} does not exist`),
620
679
  };
621
680
  }
622
681
  if (entity.kind !== "task") {
623
682
  return {
624
683
  edits: [],
625
- diagnostic: mutationDiagnostic("PTMUT-303", `entity ${mutation.id}はtaskではありません`, entity),
684
+ diagnostic: mutationDiagnostic("PTMUT-303", `entity ${mutation.id} is not a task`, entity),
626
685
  };
627
686
  }
628
687
  const lines = splitPhysicalLines(text);
@@ -637,8 +696,8 @@ export function planTaskMutationEdits(text, document, mutation) {
637
696
  ...(fieldNamed(entity, "blocked_reason") === undefined
638
697
  ? {}
639
698
  : { clear: ["blocked_reason"] }),
640
- });
699
+ }, profile);
641
700
  }
642
- return planSetTask(text, entity, mutation);
701
+ return planSetTask(text, entity, mutation, profile);
643
702
  }
644
703
  //# sourceMappingURL=task.js.map