@fulcro/types 0.1.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/LICENSE +15 -0
- package/README.md +66 -0
- package/dist/bigInteger/index.d.ts +27 -0
- package/dist/bigInteger/index.js +76 -0
- package/dist/brand/index.d.ts +25 -0
- package/dist/brand/index.js +2 -0
- package/dist/decimal/arithmetic.d.ts +99 -0
- package/dist/decimal/arithmetic.js +388 -0
- package/dist/decimal/format.d.ts +55 -0
- package/dist/decimal/format.js +195 -0
- package/dist/decimal/index.d.ts +296 -0
- package/dist/decimal/index.js +407 -0
- package/dist/decimal/parse.d.ts +15 -0
- package/dist/decimal/parse.js +80 -0
- package/dist/decimal/parts.d.ts +83 -0
- package/dist/decimal/parts.js +103 -0
- package/dist/decimal/round.d.ts +32 -0
- package/dist/decimal/round.js +132 -0
- package/dist/doublePrecisionFloat/index.d.ts +19 -0
- package/dist/doublePrecisionFloat/index.js +12 -0
- package/dist/float/index.d.ts +25 -0
- package/dist/float/index.js +61 -0
- package/dist/halfPrecisionFloat/index.d.ts +20 -0
- package/dist/halfPrecisionFloat/index.js +63 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +29 -0
- package/dist/integer/index.d.ts +163 -0
- package/dist/integer/index.js +402 -0
- package/dist/languageService/index.d.ts +21 -0
- package/dist/languageService/index.js +23 -0
- package/dist/layout/index.d.ts +33 -0
- package/dist/layout/index.js +2 -0
- package/dist/numericType/index.d.ts +174 -0
- package/dist/numericType/index.js +2 -0
- package/dist/roundingMode/index.d.ts +30 -0
- package/dist/roundingMode/index.js +29 -0
- package/dist/signedInteger/index.d.ts +40 -0
- package/dist/signedInteger/index.js +34 -0
- package/dist/singlePrecisionFloat/index.d.ts +20 -0
- package/dist/singlePrecisionFloat/index.js +15 -0
- package/dist/transformer/classify/index.d.ts +39 -0
- package/dist/transformer/classify/index.js +84 -0
- package/dist/transformer/index.d.ts +27 -0
- package/dist/transformer/index.js +30 -0
- package/dist/transformer/rewriter/index.d.ts +3 -0
- package/dist/transformer/rewriter/index.js +374 -0
- package/dist/unplugin/index.d.mts +15 -0
- package/dist/unplugin/index.mjs +31 -0
- package/dist/unsignedInteger/index.d.ts +36 -0
- package/dist/unsignedInteger/index.js +34 -0
- package/package.json +71 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OPERATOR_REWRITER = void 0;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const classify_1 = require("../classify/index.js");
|
|
9
|
+
/**
|
|
10
|
+
* The rewrite of the JavaScript operators on this package's numeric types.
|
|
11
|
+
*
|
|
12
|
+
* Every operator becomes a call to the operation that means it for the type —
|
|
13
|
+
* `a + b` on two `SignedInteger<32>` becomes `SignedInteger(32).add(a, b)`,
|
|
14
|
+
* checked for overflow; on two `Decimal`, `a.add(b)`. The call is what the
|
|
15
|
+
* checker then sees, so the result keeps its type, and an operand of any other
|
|
16
|
+
* type fails to type check as an argument: that is how "the same type only" is
|
|
17
|
+
* enforced, with the checker's own message at the site.
|
|
18
|
+
*
|
|
19
|
+
* | Written | Becomes |
|
|
20
|
+
* | ------------------------------------------------ | ------------------------------ |
|
|
21
|
+
* | `a + b`, `-`, `*`, `/`, `%`, `**` | `T.add(a, b)` … |
|
|
22
|
+
* | `a & b`, `\|`, `^`, `<<`, `>>`, `>>>` | `T.bitwiseAnd(a, b)` … |
|
|
23
|
+
* | `a < b`, `<=`, `>`, `>=` | `T.lessThan(a, b)` … |
|
|
24
|
+
* | `a === b`, `==`, `!==`, `!=` | `T.equals(a, b)`, negated |
|
|
25
|
+
* | `-a`, `+a`, `~a` | `T.negate(a)`, `a`, `T.bitwiseNot(a)` |
|
|
26
|
+
* | `++a`, `a++`, `--a`, `a--` | `T.increment` / `T.decrement` |
|
|
27
|
+
* | `a += b` and every compound assignment | `a = T.add(a, b)` … |
|
|
28
|
+
*
|
|
29
|
+
* Evaluation order and the value of each expression are those of the operator
|
|
30
|
+
* it replaces: a compound assignment evaluates its target once, and a postfix
|
|
31
|
+
* operator evaluates to the value before the change.
|
|
32
|
+
*/
|
|
33
|
+
/** Module every rewritten file imports, and the name it is imported under. */
|
|
34
|
+
const MODULE = '@fulcro/types';
|
|
35
|
+
const NAMESPACE = '__fulcroTypes';
|
|
36
|
+
/** The operation each binary operator stands for. */
|
|
37
|
+
const BINARY_OPERATIONS = new Map([
|
|
38
|
+
[typescript_1.default.SyntaxKind.PlusToken, 'add'],
|
|
39
|
+
[typescript_1.default.SyntaxKind.MinusToken, 'subtract'],
|
|
40
|
+
[typescript_1.default.SyntaxKind.AsteriskToken, 'multiply'],
|
|
41
|
+
[typescript_1.default.SyntaxKind.SlashToken, 'divide'],
|
|
42
|
+
[typescript_1.default.SyntaxKind.PercentToken, 'remainder'],
|
|
43
|
+
[typescript_1.default.SyntaxKind.AsteriskAsteriskToken, 'power'],
|
|
44
|
+
[typescript_1.default.SyntaxKind.AmpersandToken, 'bitwiseAnd'],
|
|
45
|
+
[typescript_1.default.SyntaxKind.BarToken, 'bitwiseOr'],
|
|
46
|
+
[typescript_1.default.SyntaxKind.CaretToken, 'bitwiseXor'],
|
|
47
|
+
[typescript_1.default.SyntaxKind.LessThanLessThanToken, 'shiftLeft'],
|
|
48
|
+
[typescript_1.default.SyntaxKind.GreaterThanGreaterThanToken, 'shiftRight'],
|
|
49
|
+
[
|
|
50
|
+
typescript_1.default.SyntaxKind.GreaterThanGreaterThanGreaterThanToken,
|
|
51
|
+
'shiftRightLogical',
|
|
52
|
+
],
|
|
53
|
+
[typescript_1.default.SyntaxKind.LessThanToken, 'lessThan'],
|
|
54
|
+
[typescript_1.default.SyntaxKind.LessThanEqualsToken, 'lessThanOrEqual'],
|
|
55
|
+
[typescript_1.default.SyntaxKind.GreaterThanToken, 'greaterThan'],
|
|
56
|
+
[typescript_1.default.SyntaxKind.GreaterThanEqualsToken, 'greaterThanOrEqual'],
|
|
57
|
+
]);
|
|
58
|
+
/** The operation each compound assignment applies before assigning. */
|
|
59
|
+
const COMPOUND_OPERATIONS = new Map([
|
|
60
|
+
[typescript_1.default.SyntaxKind.PlusEqualsToken, 'add'],
|
|
61
|
+
[typescript_1.default.SyntaxKind.MinusEqualsToken, 'subtract'],
|
|
62
|
+
[typescript_1.default.SyntaxKind.AsteriskEqualsToken, 'multiply'],
|
|
63
|
+
[typescript_1.default.SyntaxKind.SlashEqualsToken, 'divide'],
|
|
64
|
+
[typescript_1.default.SyntaxKind.PercentEqualsToken, 'remainder'],
|
|
65
|
+
[typescript_1.default.SyntaxKind.AsteriskAsteriskEqualsToken, 'power'],
|
|
66
|
+
[typescript_1.default.SyntaxKind.AmpersandEqualsToken, 'bitwiseAnd'],
|
|
67
|
+
[typescript_1.default.SyntaxKind.BarEqualsToken, 'bitwiseOr'],
|
|
68
|
+
[typescript_1.default.SyntaxKind.CaretEqualsToken, 'bitwiseXor'],
|
|
69
|
+
[typescript_1.default.SyntaxKind.LessThanLessThanEqualsToken, 'shiftLeft'],
|
|
70
|
+
[typescript_1.default.SyntaxKind.GreaterThanGreaterThanEqualsToken, 'shiftRight'],
|
|
71
|
+
[
|
|
72
|
+
typescript_1.default.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
|
|
73
|
+
'shiftRightLogical',
|
|
74
|
+
],
|
|
75
|
+
]);
|
|
76
|
+
/** Equality operators, and whether each is negated. */
|
|
77
|
+
const EQUALITY = new Map([
|
|
78
|
+
[typescript_1.default.SyntaxKind.EqualsEqualsEqualsToken, false],
|
|
79
|
+
[typescript_1.default.SyntaxKind.EqualsEqualsToken, false],
|
|
80
|
+
[typescript_1.default.SyntaxKind.ExclamationEqualsEqualsToken, true],
|
|
81
|
+
[typescript_1.default.SyntaxKind.ExclamationEqualsToken, true],
|
|
82
|
+
]);
|
|
83
|
+
/**
|
|
84
|
+
* The call applying an operation to operands, in the form the kind uses.
|
|
85
|
+
*
|
|
86
|
+
* @param kind Kind the operation belongs to.
|
|
87
|
+
* @param operation Name of the operation.
|
|
88
|
+
* @param operands Its operands, in order.
|
|
89
|
+
* @param separator What goes between two operands, line breaks included.
|
|
90
|
+
* @param leftIsOurs Whether the first operand is of the kind — for a decimal,
|
|
91
|
+
* whether the method can be called on it.
|
|
92
|
+
* @returns The replacement.
|
|
93
|
+
*/
|
|
94
|
+
const call = (kind, operation, operands, separator = ', ', leftIsOurs = true) => {
|
|
95
|
+
if (kind.family === 'descriptor') {
|
|
96
|
+
return [
|
|
97
|
+
`${NAMESPACE}.${kind.descriptor}.${operation}(`,
|
|
98
|
+
...interleave(operands, separator),
|
|
99
|
+
')',
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
const [receiver, ...rest] = operands;
|
|
103
|
+
if (!leftIsOurs) {
|
|
104
|
+
// The method cannot be called on an operand that is not a decimal, and
|
|
105
|
+
// the checker has to say so at the site: a function taking two
|
|
106
|
+
// decimals makes it.
|
|
107
|
+
return [
|
|
108
|
+
`((__left: ${NAMESPACE}.Decimal, __right: ${NAMESPACE}.Decimal) => __left.${operation}(__right))(`,
|
|
109
|
+
...interleave(operands, separator),
|
|
110
|
+
')',
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
return [
|
|
114
|
+
'(',
|
|
115
|
+
receiver,
|
|
116
|
+
`).${operation}(`,
|
|
117
|
+
...interleave(rest, separator),
|
|
118
|
+
')',
|
|
119
|
+
];
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Puts a separator between operands.
|
|
123
|
+
*
|
|
124
|
+
* @param operands Operands, in order.
|
|
125
|
+
* @param separator What goes between two of them.
|
|
126
|
+
* @returns The operands with separators.
|
|
127
|
+
*/
|
|
128
|
+
const interleave = (operands, separator) => operands.flatMap((operand, index) => index === 0 ? [operand] : [separator, operand]);
|
|
129
|
+
/**
|
|
130
|
+
* One, as the kind writes it, for `++` and `--` on a decimal.
|
|
131
|
+
*
|
|
132
|
+
* @returns The expression.
|
|
133
|
+
*/
|
|
134
|
+
const decimalOne = () => `${NAMESPACE}.Decimal.from(1)`;
|
|
135
|
+
/**
|
|
136
|
+
* The increment or decrement of an operand, as the kind computes it.
|
|
137
|
+
*
|
|
138
|
+
* @param kind Kind of the operand.
|
|
139
|
+
* @param increment Whether it goes up.
|
|
140
|
+
* @param operand The operand.
|
|
141
|
+
* @returns The replacement.
|
|
142
|
+
*/
|
|
143
|
+
const step = (kind, increment, operand) => kind.family === 'descriptor'
|
|
144
|
+
? call(kind, increment ? 'increment' : 'decrement', [operand])
|
|
145
|
+
: call(kind, increment ? 'add' : 'subtract', [operand, decimalOne()]);
|
|
146
|
+
/**
|
|
147
|
+
* Strips the parentheses around an expression.
|
|
148
|
+
*
|
|
149
|
+
* @param expression Expression, possibly parenthesized.
|
|
150
|
+
* @returns The expression inside.
|
|
151
|
+
*/
|
|
152
|
+
const unwrap = (expression) => typescript_1.default.isParenthesizedExpression(expression)
|
|
153
|
+
? unwrap(expression.expression)
|
|
154
|
+
: expression;
|
|
155
|
+
/**
|
|
156
|
+
* Tells whether an expression can be evaluated twice without anything
|
|
157
|
+
* observable happening: a name, `this`, or a literal.
|
|
158
|
+
*
|
|
159
|
+
* @param expression Expression to inspect.
|
|
160
|
+
* @returns `true` when evaluating it again is harmless.
|
|
161
|
+
*/
|
|
162
|
+
const isInert = (expression) => typescript_1.default.isIdentifier(expression) ||
|
|
163
|
+
expression.kind === typescript_1.default.SyntaxKind.ThisKeyword ||
|
|
164
|
+
typescript_1.default.isLiteralExpression(expression);
|
|
165
|
+
/**
|
|
166
|
+
* How an assignment target is written back to, evaluating its parts once.
|
|
167
|
+
*
|
|
168
|
+
* A name, or a member of a name, is written twice as it stands. Any other
|
|
169
|
+
* member — `items[next()]`, `load().total` — is evaluated once into the
|
|
170
|
+
* parameters of an arrow function called on the spot, which is also what keeps
|
|
171
|
+
* the order of evaluation JavaScript's.
|
|
172
|
+
*
|
|
173
|
+
* @param target The target, parentheses stripped.
|
|
174
|
+
* @returns How to wrap an assignment to it.
|
|
175
|
+
*/
|
|
176
|
+
const assignmentForm = (target) => {
|
|
177
|
+
if (typescript_1.default.isPropertyAccessExpression(target) &&
|
|
178
|
+
!isInert(target.expression)) {
|
|
179
|
+
return {
|
|
180
|
+
reference: `__target.${target.name.text}`,
|
|
181
|
+
open: ['((__target) => ('],
|
|
182
|
+
close: ['))(', target.expression, ')'],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (typescript_1.default.isElementAccessExpression(target) &&
|
|
186
|
+
!(isInert(target.expression) && isInert(target.argumentExpression))) {
|
|
187
|
+
return {
|
|
188
|
+
reference: '__target[__key]',
|
|
189
|
+
open: ['((__target, __key) => ('],
|
|
190
|
+
close: ['))(', target.expression, ', ', target.argumentExpression, ')'],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return { reference: target, open: ['('], close: [')'] };
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Tells whether a type is one a string concatenation would produce, which
|
|
197
|
+
* `+` then means instead of addition.
|
|
198
|
+
*
|
|
199
|
+
* @param type Type of an operand.
|
|
200
|
+
* @returns `true` for a string.
|
|
201
|
+
*/
|
|
202
|
+
const isString = (type) => (type.flags & typescript_1.default.TypeFlags.StringLike) !== 0;
|
|
203
|
+
/**
|
|
204
|
+
* Tells whether a type is a plain number or bigint — the kind of operand an
|
|
205
|
+
* equality with one of ours has to refuse, rather than leave to a comparison
|
|
206
|
+
* that would quietly succeed.
|
|
207
|
+
*
|
|
208
|
+
* @param type Type of an operand.
|
|
209
|
+
* @returns `true` for a number or a bigint.
|
|
210
|
+
*/
|
|
211
|
+
const isNumeric = (type) => (type.flags &
|
|
212
|
+
(typescript_1.default.TypeFlags.NumberLike | typescript_1.default.TypeFlags.BigIntLike)) !==
|
|
213
|
+
0;
|
|
214
|
+
/**
|
|
215
|
+
* Rewrites a binary expression.
|
|
216
|
+
*
|
|
217
|
+
* @param node The expression.
|
|
218
|
+
* @param context The file and its checker.
|
|
219
|
+
* @returns The replacement, or `null`.
|
|
220
|
+
*/
|
|
221
|
+
const rewriteBinary = (node, context) => {
|
|
222
|
+
const { checker } = context;
|
|
223
|
+
const operator = node.operatorToken.kind;
|
|
224
|
+
const leftType = checker.getTypeAtLocation(node.left);
|
|
225
|
+
const rightType = checker.getTypeAtLocation(node.right);
|
|
226
|
+
const left = (0, classify_1.classify)(leftType, checker, node.left);
|
|
227
|
+
const right = (0, classify_1.classify)(rightType, checker, node.right);
|
|
228
|
+
const kind = left ?? right;
|
|
229
|
+
if (kind === null)
|
|
230
|
+
return null;
|
|
231
|
+
const separator = `, ${context.lineBreaks(node.left.end, node.right.getStart(context.sourceFile))}`;
|
|
232
|
+
const compound = COMPOUND_OPERATIONS.get(operator);
|
|
233
|
+
if (compound !== undefined) {
|
|
234
|
+
const target = unwrap(node.left);
|
|
235
|
+
const form = assignmentForm(target);
|
|
236
|
+
return [
|
|
237
|
+
...form.open,
|
|
238
|
+
form.reference,
|
|
239
|
+
' = ',
|
|
240
|
+
...call(kind, compound, [form.reference, node.right], separator, left !== null),
|
|
241
|
+
...form.close,
|
|
242
|
+
];
|
|
243
|
+
}
|
|
244
|
+
const negated = EQUALITY.get(operator);
|
|
245
|
+
if (negated !== undefined) {
|
|
246
|
+
// An equality with something that is not a number at all — `null`, an
|
|
247
|
+
// object — is a question about identity, and stays one.
|
|
248
|
+
const comparable = (left !== null || isNumeric(leftType)) &&
|
|
249
|
+
(right !== null || isNumeric(rightType));
|
|
250
|
+
if (!comparable)
|
|
251
|
+
return null;
|
|
252
|
+
const equals = call(kind, 'equals', [node.left, node.right], separator, left !== null);
|
|
253
|
+
return negated ? ['(!', ...equals, ')'] : equals;
|
|
254
|
+
}
|
|
255
|
+
const operation = BINARY_OPERATIONS.get(operator);
|
|
256
|
+
if (operation === undefined)
|
|
257
|
+
return null;
|
|
258
|
+
if (operator === typescript_1.default.SyntaxKind.PlusToken &&
|
|
259
|
+
(isString(leftType) || isString(rightType))) {
|
|
260
|
+
// Concatenation, not addition. A primitive-backed value concatenates as
|
|
261
|
+
// a number does; a decimal refuses the implicit conversion, so its text
|
|
262
|
+
// is asked for explicitly.
|
|
263
|
+
if (kind.family !== 'decimal')
|
|
264
|
+
return null;
|
|
265
|
+
const text = (operand, ours) => ours ? ['(', operand, ').toString()'] : [operand];
|
|
266
|
+
return [
|
|
267
|
+
...text(node.left, left !== null),
|
|
268
|
+
` + ${context.lineBreaks(node.left.end, node.right.getStart(context.sourceFile))}`,
|
|
269
|
+
...text(node.right, right !== null),
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
return call(kind, operation, [node.left, node.right], separator, left !== null);
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Rewrites an increment or a decrement, written before or after its operand.
|
|
276
|
+
*
|
|
277
|
+
* @param node The expression.
|
|
278
|
+
* @param operand Its operand.
|
|
279
|
+
* @param increment Whether it goes up.
|
|
280
|
+
* @param postfix Whether it was written after the operand.
|
|
281
|
+
* @param context The file and its checker.
|
|
282
|
+
* @returns The replacement, or `null`.
|
|
283
|
+
*/
|
|
284
|
+
const rewriteStep = (node, operand, increment, postfix, context) => {
|
|
285
|
+
const kind = (0, classify_1.classify)(context.checker.getTypeAtLocation(operand), context.checker, operand);
|
|
286
|
+
if (kind === null)
|
|
287
|
+
return null;
|
|
288
|
+
const target = unwrap(operand);
|
|
289
|
+
const form = assignmentForm(target);
|
|
290
|
+
// Where the value of the expression is thrown away — a statement of its
|
|
291
|
+
// own, the step of a `for` — the prefix form does the same work.
|
|
292
|
+
const valueUnused = typescript_1.default.isExpressionStatement(node.parent) ||
|
|
293
|
+
(typescript_1.default.isForStatement(node.parent) &&
|
|
294
|
+
node.parent.incrementor === node);
|
|
295
|
+
if (!postfix || valueUnused) {
|
|
296
|
+
return [
|
|
297
|
+
...form.open,
|
|
298
|
+
form.reference,
|
|
299
|
+
' = ',
|
|
300
|
+
...step(kind, increment, form.reference),
|
|
301
|
+
...form.close,
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
// The value before the step is taken once, as a default parameter, so the
|
|
305
|
+
// target is read once and the expression still evaluates to it.
|
|
306
|
+
if (typeof form.reference === 'string') {
|
|
307
|
+
const [head] = form.open;
|
|
308
|
+
const parameters = head.replace(') => (', `, __previous = ${form.reference}) => (`);
|
|
309
|
+
return [
|
|
310
|
+
parameters,
|
|
311
|
+
'(',
|
|
312
|
+
form.reference,
|
|
313
|
+
' = ',
|
|
314
|
+
...step(kind, increment, '__previous'),
|
|
315
|
+
'), __previous',
|
|
316
|
+
...form.close,
|
|
317
|
+
];
|
|
318
|
+
}
|
|
319
|
+
return [
|
|
320
|
+
'((__previous) => ((',
|
|
321
|
+
target,
|
|
322
|
+
' = ',
|
|
323
|
+
...step(kind, increment, '__previous'),
|
|
324
|
+
'), __previous))(',
|
|
325
|
+
target,
|
|
326
|
+
')',
|
|
327
|
+
];
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* Rewrites a unary expression written before its operand.
|
|
331
|
+
*
|
|
332
|
+
* @param node The expression.
|
|
333
|
+
* @param context The file and its checker.
|
|
334
|
+
* @returns The replacement, or `null`.
|
|
335
|
+
*/
|
|
336
|
+
const rewritePrefix = (node, context) => {
|
|
337
|
+
switch (node.operator) {
|
|
338
|
+
case typescript_1.default.SyntaxKind.PlusPlusToken:
|
|
339
|
+
return rewriteStep(node, node.operand, true, false, context);
|
|
340
|
+
case typescript_1.default.SyntaxKind.MinusMinusToken:
|
|
341
|
+
return rewriteStep(node, node.operand, false, false, context);
|
|
342
|
+
}
|
|
343
|
+
const kind = (0, classify_1.classify)(context.checker.getTypeAtLocation(node.operand), context.checker, node.operand);
|
|
344
|
+
if (kind === null)
|
|
345
|
+
return null;
|
|
346
|
+
switch (node.operator) {
|
|
347
|
+
case typescript_1.default.SyntaxKind.MinusToken:
|
|
348
|
+
return call(kind, 'negate', [node.operand]);
|
|
349
|
+
case typescript_1.default.SyntaxKind.TildeToken:
|
|
350
|
+
return call(kind, 'bitwiseNot', [node.operand]);
|
|
351
|
+
case typescript_1.default.SyntaxKind.PlusToken:
|
|
352
|
+
// The identity, which on a `number` would still widen the type.
|
|
353
|
+
return ['(', node.operand, ')'];
|
|
354
|
+
default:
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
/** The rewriter of the operators on this package's numeric types. */
|
|
359
|
+
exports.OPERATOR_REWRITER = {
|
|
360
|
+
module: MODULE,
|
|
361
|
+
namespace: NAMESPACE,
|
|
362
|
+
rewrite: (node, context) => {
|
|
363
|
+
if (typescript_1.default.isBinaryExpression(node)) {
|
|
364
|
+
return rewriteBinary(node, context);
|
|
365
|
+
}
|
|
366
|
+
if (typescript_1.default.isPrefixUnaryExpression(node)) {
|
|
367
|
+
return rewritePrefix(node, context);
|
|
368
|
+
}
|
|
369
|
+
if (typescript_1.default.isPostfixUnaryExpression(node)) {
|
|
370
|
+
return rewriteStep(node, node.operand, node.operator === typescript_1.default.SyntaxKind.PlusPlusToken, true, context);
|
|
371
|
+
}
|
|
372
|
+
return null;
|
|
373
|
+
},
|
|
374
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type { PluginOptions } from '@fulcro/transform-core/unplugin';
|
|
2
|
+
/** The factory itself, for a bundler not covered below. */
|
|
3
|
+
export declare const unpluginFactory: import("unplugin").UnpluginFactory<import("@fulcro/transform-core").TransformCoreOptions | undefined>;
|
|
4
|
+
/** Adapter for Vite, which is also what vitest runs on. */
|
|
5
|
+
export declare const vite: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => import("vite").Plugin<any> | import("vite").Plugin<any>[];
|
|
6
|
+
/** Adapter for Rollup. */
|
|
7
|
+
export declare const rollup: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => any;
|
|
8
|
+
/** Adapter for Webpack. */
|
|
9
|
+
export declare const webpack: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => WebpackPluginInstance;
|
|
10
|
+
/** Adapter for Rspack. */
|
|
11
|
+
export declare const rspack: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => RspackPluginInstance;
|
|
12
|
+
/** Adapter for esbuild. */
|
|
13
|
+
export declare const esbuild: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => EsbuildPlugin;
|
|
14
|
+
/** Adapter for Farm. */
|
|
15
|
+
export declare const farm: (options?: import("@fulcro/transform-core").TransformCoreOptions | undefined) => JsPlugin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createRewriterUnplugin } from '@fulcro/transform-core/unplugin';
|
|
2
|
+
import { OPERATOR_REWRITER } from '../transformer/rewriter/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bundler plugin giving the operators their meaning on this package's numeric
|
|
5
|
+
* types, for Vite, Rollup, Webpack, esbuild, Rspack and Farm:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { vite as fulcroTypes } from '@fulcro/types/unplugin';
|
|
9
|
+
*
|
|
10
|
+
* export default defineConfig({ plugins: [fulcroTypes()] });
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* It runs before the bundler erases the types, and it reads the whole program:
|
|
14
|
+
* whether `c + d` in one file is ours depends on how `c` was declared in
|
|
15
|
+
* another.
|
|
16
|
+
*/
|
|
17
|
+
const plugins = createRewriterUnplugin(OPERATOR_REWRITER, 'fulcro-types');
|
|
18
|
+
/** The factory itself, for a bundler not covered below. */
|
|
19
|
+
export const unpluginFactory = plugins.unpluginFactory;
|
|
20
|
+
/** Adapter for Vite, which is also what vitest runs on. */
|
|
21
|
+
export const vite = plugins.vite;
|
|
22
|
+
/** Adapter for Rollup. */
|
|
23
|
+
export const rollup = plugins.rollup;
|
|
24
|
+
/** Adapter for Webpack. */
|
|
25
|
+
export const webpack = plugins.webpack;
|
|
26
|
+
/** Adapter for Rspack. */
|
|
27
|
+
export const rspack = plugins.rspack;
|
|
28
|
+
/** Adapter for esbuild. */
|
|
29
|
+
export const esbuild = plugins.esbuild;
|
|
30
|
+
/** Adapter for Farm. */
|
|
31
|
+
export const farm = plugins.farm;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Branded } from '../brand/index.js';
|
|
2
|
+
import { type ByteSize, type IntegerRepresentation, type IntegerType, type IntegerWidth } from '../integer/index.js';
|
|
3
|
+
import type { Layout } from '../layout/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* An integer of `N` bits with no sign: from 0 to 2^N - 1.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const count: UnsignedInteger<16> = UnsignedInteger(16).from(65_535);
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Carried by a `number` up to 32 bits and by a `bigint` from 64. Widths are a
|
|
12
|
+
* parameter, not a list of names: there is no `UnsignedInteger16`, and no `u16`.
|
|
13
|
+
*
|
|
14
|
+
* @template N Width, in bits.
|
|
15
|
+
*/
|
|
16
|
+
export type UnsignedInteger<N extends IntegerWidth> = Branded<IntegerRepresentation<N>, `UnsignedInteger${N}`> & Layout<ByteSize<N>, ByteSize<N>>;
|
|
17
|
+
/**
|
|
18
|
+
* The descriptor of an unsigned integer width: conversion, recognition and
|
|
19
|
+
* checked arithmetic.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const Byte = UnsignedInteger(8);
|
|
23
|
+
*
|
|
24
|
+
* Byte.from(-1); // RangeError: outside [0, 255]
|
|
25
|
+
* Byte.wrap(-1); // 255
|
|
26
|
+
* Byte.subtract(Byte.from(0), Byte.from(1)); // RangeError
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Calling it twice with the same width returns the same object.
|
|
30
|
+
*
|
|
31
|
+
* @template N Width, in bits.
|
|
32
|
+
* @param width Width, in bits.
|
|
33
|
+
* @returns The descriptor of that width.
|
|
34
|
+
* @throws {RangeError} When the width is not 8, 16, 32, 64 or 128.
|
|
35
|
+
*/
|
|
36
|
+
export declare const UnsignedInteger: <N extends IntegerWidth>(width: N) => IntegerType<UnsignedInteger<N>>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnsignedInteger = void 0;
|
|
4
|
+
const integer_1 = require("../integer/index.js");
|
|
5
|
+
/** Descriptors already built, so a width is described by one object. */
|
|
6
|
+
const descriptors = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* The descriptor of an unsigned integer width: conversion, recognition and
|
|
9
|
+
* checked arithmetic.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const Byte = UnsignedInteger(8);
|
|
13
|
+
*
|
|
14
|
+
* Byte.from(-1); // RangeError: outside [0, 255]
|
|
15
|
+
* Byte.wrap(-1); // 255
|
|
16
|
+
* Byte.subtract(Byte.from(0), Byte.from(1)); // RangeError
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Calling it twice with the same width returns the same object.
|
|
20
|
+
*
|
|
21
|
+
* @template N Width, in bits.
|
|
22
|
+
* @param width Width, in bits.
|
|
23
|
+
* @returns The descriptor of that width.
|
|
24
|
+
* @throws {RangeError} When the width is not 8, 16, 32, 64 or 128.
|
|
25
|
+
*/
|
|
26
|
+
const UnsignedInteger = (width) => {
|
|
27
|
+
let descriptor = descriptors.get(width);
|
|
28
|
+
if (descriptor === undefined) {
|
|
29
|
+
descriptor = (0, integer_1.createIntegerType)(false, width, `UnsignedInteger<${width}>`);
|
|
30
|
+
descriptors.set(width, descriptor);
|
|
31
|
+
}
|
|
32
|
+
return descriptor;
|
|
33
|
+
};
|
|
34
|
+
exports.UnsignedInteger = UnsignedInteger;
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fulcro/types",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Numeric types with a defined range and layout: fixed-width integers, half, single and double precision floats, and a decimal128 Decimal.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"integer",
|
|
7
|
+
"float",
|
|
8
|
+
"decimal",
|
|
9
|
+
"decimal128",
|
|
10
|
+
"numeric",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"author": "diguu <rodrigogeribola@hotmail.com>",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./transformer": {
|
|
23
|
+
"types": "./dist/transformer/index.d.ts",
|
|
24
|
+
"default": "./dist/transformer/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./unplugin": {
|
|
27
|
+
"types": "./dist/unplugin/index.d.mts",
|
|
28
|
+
"default": "./dist/unplugin/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./language-service": {
|
|
31
|
+
"types": "./dist/languageService/index.d.ts",
|
|
32
|
+
"default": "./dist/languageService/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@fulcro/transform-core": "^0.10.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"typescript": ">=5.3.3 <7"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"typescript": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/DigUu-RL/fulcro.git",
|
|
60
|
+
"directory": "packages/types"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://github.com/DigUu-RL/fulcro/tree/main/packages/types#readme",
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/DigUu-RL/fulcro/issues"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
68
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
69
|
+
"prepublishOnly": "npm run build"
|
|
70
|
+
}
|
|
71
|
+
}
|