@prisma-next/sql-contract-psl 0.5.0-dev.8 → 0.5.0-dev.81
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/README.md +9 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -3
- package/dist/{interpreter-iFCRN9nb.mjs → interpreter-C9MPo8FK.mjs} +358 -76
- package/dist/interpreter-C9MPo8FK.mjs.map +1 -0
- package/dist/provider.d.mts +2 -2
- package/dist/provider.d.mts.map +1 -1
- package/dist/provider.mjs +3 -6
- package/dist/provider.mjs.map +1 -1
- package/package.json +13 -12
- package/src/interpreter.ts +128 -28
- package/src/provider.ts +3 -5
- package/src/psl-attribute-parsing.ts +14 -5
- package/src/psl-authoring-arguments.ts +6 -0
- package/src/psl-column-resolution.ts +228 -37
- package/src/psl-field-resolution.ts +138 -17
- package/src/psl-relation-resolution.ts +3 -0
- package/dist/interpreter-iFCRN9nb.mjs.map +0 -1
package/src/interpreter.ts
CHANGED
|
@@ -35,11 +35,13 @@ import {
|
|
|
35
35
|
type ForeignKeyNode,
|
|
36
36
|
type IndexNode,
|
|
37
37
|
type ModelNode,
|
|
38
|
+
type PrimaryKeyNode,
|
|
38
39
|
type UniqueConstraintNode,
|
|
39
40
|
} from '@prisma-next/sql-contract-ts/contract-builder';
|
|
40
41
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
41
42
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
42
43
|
import {
|
|
44
|
+
findDuplicateFieldName,
|
|
43
45
|
getAttribute,
|
|
44
46
|
getPositionalArgument,
|
|
45
47
|
mapFieldNamesToColumns,
|
|
@@ -77,19 +79,19 @@ import {
|
|
|
77
79
|
|
|
78
80
|
export interface InterpretPslDocumentToSqlContractInput {
|
|
79
81
|
readonly document: ParsePslDocumentResult;
|
|
80
|
-
readonly target: TargetPackRef<'sql',
|
|
82
|
+
readonly target: TargetPackRef<'sql', string>;
|
|
81
83
|
readonly scalarTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
82
84
|
readonly composedExtensionPacks?: readonly string[];
|
|
83
|
-
readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql',
|
|
85
|
+
readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];
|
|
84
86
|
readonly controlMutationDefaults?: ControlMutationDefaults;
|
|
85
87
|
readonly authoringContributions?: AuthoringContributions;
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
function buildComposedExtensionPackRefs(
|
|
89
|
-
target: TargetPackRef<'sql',
|
|
91
|
+
target: TargetPackRef<'sql', string>,
|
|
90
92
|
extensionIds: readonly string[],
|
|
91
|
-
extensionPackRefs: readonly ExtensionPackRef<'sql',
|
|
92
|
-
): Record<string, ExtensionPackRef<'sql',
|
|
93
|
+
extensionPackRefs: readonly ExtensionPackRef<'sql', string>[] = [],
|
|
94
|
+
): Record<string, ExtensionPackRef<'sql', string>> | undefined {
|
|
93
95
|
if (extensionIds.length === 0) {
|
|
94
96
|
return undefined;
|
|
95
97
|
}
|
|
@@ -106,7 +108,7 @@ function buildComposedExtensionPackRefs(
|
|
|
106
108
|
familyId: target.familyId,
|
|
107
109
|
targetId: target.targetId,
|
|
108
110
|
version: '0.0.1',
|
|
109
|
-
} satisfies ExtensionPackRef<'sql',
|
|
111
|
+
} satisfies ExtensionPackRef<'sql', string>),
|
|
110
112
|
]),
|
|
111
113
|
);
|
|
112
114
|
}
|
|
@@ -219,6 +221,7 @@ function validateNamedTypeAttributes(input: {
|
|
|
219
221
|
readonly sourceId: string;
|
|
220
222
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
221
223
|
readonly composedExtensions: ReadonlySet<string>;
|
|
224
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
222
225
|
readonly allowDbNativeType: boolean;
|
|
223
226
|
readonly familyId: string;
|
|
224
227
|
readonly targetId: string;
|
|
@@ -250,6 +253,7 @@ function validateNamedTypeAttributes(input: {
|
|
|
250
253
|
const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
|
|
251
254
|
familyId: input.familyId,
|
|
252
255
|
targetId: input.targetId,
|
|
256
|
+
authoringContributions: input.authoringContributions,
|
|
253
257
|
});
|
|
254
258
|
if (uncomposedNamespace) {
|
|
255
259
|
reportUncomposedNamespace({
|
|
@@ -289,6 +293,7 @@ function resolveNamedTypeDeclarations(input: ResolveNamedTypeDeclarationsInput):
|
|
|
289
293
|
sourceId: input.sourceId,
|
|
290
294
|
diagnostics: input.diagnostics,
|
|
291
295
|
composedExtensions: input.composedExtensions,
|
|
296
|
+
authoringContributions: input.authoringContributions,
|
|
292
297
|
allowDbNativeType: false,
|
|
293
298
|
familyId: input.familyId,
|
|
294
299
|
targetId: input.targetId,
|
|
@@ -367,6 +372,7 @@ function resolveNamedTypeDeclarations(input: ResolveNamedTypeDeclarationsInput):
|
|
|
367
372
|
sourceId: input.sourceId,
|
|
368
373
|
diagnostics: input.diagnostics,
|
|
369
374
|
composedExtensions: input.composedExtensions,
|
|
375
|
+
authoringContributions: input.authoringContributions,
|
|
370
376
|
allowDbNativeType: true,
|
|
371
377
|
familyId: input.familyId,
|
|
372
378
|
targetId: input.targetId,
|
|
@@ -460,18 +466,24 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
460
466
|
scalarTypeDescriptors: input.scalarTypeDescriptors,
|
|
461
467
|
});
|
|
462
468
|
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
const primaryKeyName = primaryKeyFields.length === 1 ? primaryKeyFields[0]?.idName : undefined;
|
|
466
|
-
const isVariantModel = model.attributes.some((attr) => attr.name === 'base');
|
|
467
|
-
if (primaryKeyColumns.length === 0 && !isVariantModel) {
|
|
469
|
+
const inlineIdFields = resolvedFields.filter((field) => field.isId);
|
|
470
|
+
if (inlineIdFields.length > 1) {
|
|
468
471
|
diagnostics.push({
|
|
469
|
-
code: '
|
|
470
|
-
message: `Model "${model.name}"
|
|
472
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
473
|
+
message: `Model "${model.name}" cannot declare inline @id on multiple fields; use model-level @@id([...]) for composite identity`,
|
|
471
474
|
sourceId,
|
|
472
475
|
span: model.span,
|
|
473
476
|
});
|
|
474
477
|
}
|
|
478
|
+
const singleInlineIdField = inlineIdFields.length === 1 ? inlineIdFields[0] : undefined;
|
|
479
|
+
let primaryKey: PrimaryKeyNode | undefined = singleInlineIdField
|
|
480
|
+
? {
|
|
481
|
+
columns: [singleInlineIdField.columnName],
|
|
482
|
+
...ifDefined('name', singleInlineIdField.idName),
|
|
483
|
+
}
|
|
484
|
+
: undefined;
|
|
485
|
+
const hasInlinePrimaryKey = primaryKey !== undefined;
|
|
486
|
+
let blockPrimaryKeyDeclared = false;
|
|
475
487
|
|
|
476
488
|
const resultBackrelationCandidates: ModelBackrelationCandidate[] = [];
|
|
477
489
|
for (const field of model.fields) {
|
|
@@ -483,6 +495,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
483
495
|
field,
|
|
484
496
|
sourceId,
|
|
485
497
|
composedExtensions: input.composedExtensions,
|
|
498
|
+
authoringContributions: input.authoringContributions,
|
|
486
499
|
diagnostics,
|
|
487
500
|
familyId: input.familyId,
|
|
488
501
|
targetId: input.targetId,
|
|
@@ -557,17 +570,107 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
557
570
|
if (modelAttribute.name === 'discriminator' || modelAttribute.name === 'base') {
|
|
558
571
|
continue;
|
|
559
572
|
}
|
|
573
|
+
const attributeLabel = `Model "${model.name}" @@${modelAttribute.name}`;
|
|
574
|
+
if (modelAttribute.name === 'id') {
|
|
575
|
+
if (blockPrimaryKeyDeclared) {
|
|
576
|
+
diagnostics.push({
|
|
577
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
578
|
+
message: `Model "${model.name}" declares @@id more than once`,
|
|
579
|
+
sourceId,
|
|
580
|
+
span: modelAttribute.span,
|
|
581
|
+
});
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
if (hasInlinePrimaryKey) {
|
|
585
|
+
diagnostics.push({
|
|
586
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
587
|
+
message: `Model "${model.name}" cannot declare both field-level @id and model-level @@id`,
|
|
588
|
+
sourceId,
|
|
589
|
+
span: modelAttribute.span,
|
|
590
|
+
});
|
|
591
|
+
blockPrimaryKeyDeclared = true;
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
const fieldNames = parseAttributeFieldList({
|
|
595
|
+
attribute: modelAttribute,
|
|
596
|
+
sourceId,
|
|
597
|
+
diagnostics,
|
|
598
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
599
|
+
entityLabel: attributeLabel,
|
|
600
|
+
});
|
|
601
|
+
if (!fieldNames) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
605
|
+
if (duplicateFieldName !== undefined) {
|
|
606
|
+
diagnostics.push({
|
|
607
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
608
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
609
|
+
sourceId,
|
|
610
|
+
span: modelAttribute.span,
|
|
611
|
+
});
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
const nullableFieldName = fieldNames.find(
|
|
615
|
+
(name) => model.fields.find((f) => f.name === name)?.optional === true,
|
|
616
|
+
);
|
|
617
|
+
if (nullableFieldName !== undefined) {
|
|
618
|
+
diagnostics.push({
|
|
619
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
620
|
+
message: `${attributeLabel} cannot include optional field "${nullableFieldName}"; primary key columns must be NOT NULL`,
|
|
621
|
+
sourceId,
|
|
622
|
+
span: modelAttribute.span,
|
|
623
|
+
});
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const columnNames = mapFieldNamesToColumns({
|
|
627
|
+
modelName: model.name,
|
|
628
|
+
fieldNames,
|
|
629
|
+
mapping,
|
|
630
|
+
sourceId,
|
|
631
|
+
diagnostics,
|
|
632
|
+
span: modelAttribute.span,
|
|
633
|
+
entityLabel: attributeLabel,
|
|
634
|
+
});
|
|
635
|
+
if (!columnNames) {
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
const constraintName = parseConstraintMapArgument({
|
|
639
|
+
attribute: modelAttribute,
|
|
640
|
+
sourceId,
|
|
641
|
+
diagnostics,
|
|
642
|
+
entityLabel: attributeLabel,
|
|
643
|
+
span: modelAttribute.span,
|
|
644
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
645
|
+
});
|
|
646
|
+
primaryKey = {
|
|
647
|
+
columns: columnNames,
|
|
648
|
+
...ifDefined('name', constraintName),
|
|
649
|
+
};
|
|
650
|
+
blockPrimaryKeyDeclared = true;
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
560
653
|
if (modelAttribute.name === 'unique' || modelAttribute.name === 'index') {
|
|
561
654
|
const fieldNames = parseAttributeFieldList({
|
|
562
655
|
attribute: modelAttribute,
|
|
563
656
|
sourceId,
|
|
564
657
|
diagnostics,
|
|
565
658
|
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
566
|
-
|
|
659
|
+
entityLabel: attributeLabel,
|
|
567
660
|
});
|
|
568
661
|
if (!fieldNames) {
|
|
569
662
|
continue;
|
|
570
663
|
}
|
|
664
|
+
const duplicateFieldName = findDuplicateFieldName(fieldNames);
|
|
665
|
+
if (duplicateFieldName !== undefined) {
|
|
666
|
+
diagnostics.push({
|
|
667
|
+
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
668
|
+
message: `${attributeLabel} list contains duplicate field "${duplicateFieldName}"`,
|
|
669
|
+
sourceId,
|
|
670
|
+
span: modelAttribute.span,
|
|
671
|
+
});
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
571
674
|
const columnNames = mapFieldNamesToColumns({
|
|
572
675
|
modelName: model.name,
|
|
573
676
|
fieldNames,
|
|
@@ -575,7 +678,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
575
678
|
sourceId,
|
|
576
679
|
diagnostics,
|
|
577
680
|
span: modelAttribute.span,
|
|
578
|
-
|
|
681
|
+
entityLabel: attributeLabel,
|
|
579
682
|
});
|
|
580
683
|
if (!columnNames) {
|
|
581
684
|
continue;
|
|
@@ -584,7 +687,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
584
687
|
attribute: modelAttribute,
|
|
585
688
|
sourceId,
|
|
586
689
|
diagnostics,
|
|
587
|
-
entityLabel:
|
|
690
|
+
entityLabel: attributeLabel,
|
|
588
691
|
span: modelAttribute.span,
|
|
589
692
|
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
590
693
|
});
|
|
@@ -604,7 +707,11 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
604
707
|
const uncomposedNamespace = checkUncomposedNamespace(
|
|
605
708
|
modelAttribute.name,
|
|
606
709
|
input.composedExtensions,
|
|
607
|
-
{
|
|
710
|
+
{
|
|
711
|
+
familyId: input.familyId,
|
|
712
|
+
targetId: input.targetId,
|
|
713
|
+
authoringContributions: input.authoringContributions,
|
|
714
|
+
},
|
|
608
715
|
);
|
|
609
716
|
if (uncomposedNamespace) {
|
|
610
717
|
reportUncomposedNamespace({
|
|
@@ -678,7 +785,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
678
785
|
sourceId,
|
|
679
786
|
diagnostics,
|
|
680
787
|
span: relationAttribute.relation.span,
|
|
681
|
-
|
|
788
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`,
|
|
682
789
|
});
|
|
683
790
|
if (!localColumns) {
|
|
684
791
|
continue;
|
|
@@ -690,7 +797,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
690
797
|
sourceId,
|
|
691
798
|
diagnostics,
|
|
692
799
|
span: relationAttribute.relation.span,
|
|
693
|
-
|
|
800
|
+
entityLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`,
|
|
694
801
|
});
|
|
695
802
|
if (!referencedColumns) {
|
|
696
803
|
continue;
|
|
@@ -762,16 +869,9 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
762
869
|
descriptor: resolvedField.descriptor,
|
|
763
870
|
nullable: resolvedField.field.optional,
|
|
764
871
|
...ifDefined('default', resolvedField.defaultValue),
|
|
765
|
-
...ifDefined('
|
|
872
|
+
...ifDefined('executionDefaults', resolvedField.executionDefaults),
|
|
766
873
|
})),
|
|
767
|
-
...(
|
|
768
|
-
? {
|
|
769
|
-
id: {
|
|
770
|
-
columns: primaryKeyColumns,
|
|
771
|
-
...ifDefined('name', primaryKeyName),
|
|
772
|
-
},
|
|
773
|
-
}
|
|
774
|
-
: {}),
|
|
874
|
+
...ifDefined('id', primaryKey),
|
|
775
875
|
...(uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {}),
|
|
776
876
|
...(indexNodes.length > 0 ? { indexes: indexNodes } : {}),
|
|
777
877
|
...(foreignKeyNodes.length > 0 ? { foreignKeys: foreignKeyNodes } : {}),
|
package/src/provider.ts
CHANGED
|
@@ -10,8 +10,8 @@ import type { ColumnDescriptor } from './psl-column-resolution';
|
|
|
10
10
|
|
|
11
11
|
export interface PrismaContractOptions {
|
|
12
12
|
readonly output?: string;
|
|
13
|
-
readonly target: TargetPackRef<'sql',
|
|
14
|
-
readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql',
|
|
13
|
+
readonly target: TargetPackRef<'sql', string>;
|
|
14
|
+
readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function buildColumnDescriptorMap(
|
|
@@ -20,9 +20,7 @@ function buildColumnDescriptorMap(
|
|
|
20
20
|
): ReadonlyMap<string, ColumnDescriptor> {
|
|
21
21
|
const result = new Map<string, ColumnDescriptor>();
|
|
22
22
|
for (const [typeName, codecId] of scalarTypeDescriptors) {
|
|
23
|
-
const
|
|
24
|
-
if (!codec) continue;
|
|
25
|
-
const nativeType = codec.targetTypes[0];
|
|
23
|
+
const nativeType = codecLookup.targetTypesFor(codecId)?.[0];
|
|
26
24
|
if (nativeType === undefined) continue;
|
|
27
25
|
result.set(typeName, { codecId, nativeType });
|
|
28
26
|
}
|
|
@@ -251,13 +251,13 @@ export function parseAttributeFieldList(input: {
|
|
|
251
251
|
readonly sourceId: string;
|
|
252
252
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
253
253
|
readonly code: string;
|
|
254
|
-
readonly
|
|
254
|
+
readonly entityLabel: string;
|
|
255
255
|
}): readonly string[] | undefined {
|
|
256
256
|
const raw = getNamedArgument(input.attribute, 'fields') ?? getPositionalArgument(input.attribute);
|
|
257
257
|
if (!raw) {
|
|
258
258
|
input.diagnostics.push({
|
|
259
259
|
code: input.code,
|
|
260
|
-
message: `${input.
|
|
260
|
+
message: `${input.entityLabel} requires fields list argument`,
|
|
261
261
|
sourceId: input.sourceId,
|
|
262
262
|
span: input.attribute.span,
|
|
263
263
|
});
|
|
@@ -267,7 +267,7 @@ export function parseAttributeFieldList(input: {
|
|
|
267
267
|
if (!fields || fields.length === 0) {
|
|
268
268
|
input.diagnostics.push({
|
|
269
269
|
code: input.code,
|
|
270
|
-
message: `${input.
|
|
270
|
+
message: `${input.entityLabel} requires bracketed field list argument`,
|
|
271
271
|
sourceId: input.sourceId,
|
|
272
272
|
span: input.attribute.span,
|
|
273
273
|
});
|
|
@@ -276,6 +276,15 @@ export function parseAttributeFieldList(input: {
|
|
|
276
276
|
return fields;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
export function findDuplicateFieldName(fieldNames: readonly string[]): string | undefined {
|
|
280
|
+
const seen = new Set<string>();
|
|
281
|
+
for (const name of fieldNames) {
|
|
282
|
+
if (seen.has(name)) return name;
|
|
283
|
+
seen.add(name);
|
|
284
|
+
}
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
|
|
279
288
|
export function mapFieldNamesToColumns(input: {
|
|
280
289
|
readonly modelName: string;
|
|
281
290
|
readonly fieldNames: readonly string[];
|
|
@@ -283,7 +292,7 @@ export function mapFieldNamesToColumns(input: {
|
|
|
283
292
|
readonly sourceId: string;
|
|
284
293
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
285
294
|
readonly span: PslSpan;
|
|
286
|
-
readonly
|
|
295
|
+
readonly entityLabel: string;
|
|
287
296
|
}): readonly string[] | undefined {
|
|
288
297
|
const columns: string[] = [];
|
|
289
298
|
for (const fieldName of input.fieldNames) {
|
|
@@ -291,7 +300,7 @@ export function mapFieldNamesToColumns(input: {
|
|
|
291
300
|
if (!columnName) {
|
|
292
301
|
input.diagnostics.push({
|
|
293
302
|
code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',
|
|
294
|
-
message: `${input.
|
|
303
|
+
message: `${input.entityLabel} references unknown field "${input.modelName}.${fieldName}"`,
|
|
295
304
|
sourceId: input.sourceId,
|
|
296
305
|
span: input.span,
|
|
297
306
|
});
|
|
@@ -311,6 +311,12 @@ function parsePslAuthoringArgumentValue(
|
|
|
311
311
|
switch (descriptor.kind) {
|
|
312
312
|
case 'string':
|
|
313
313
|
return unquoteStringLiteral(rawValue);
|
|
314
|
+
case 'boolean': {
|
|
315
|
+
const trimmed = rawValue.trim();
|
|
316
|
+
if (trimmed === 'true') return true;
|
|
317
|
+
if (trimmed === 'false') return false;
|
|
318
|
+
return INVALID_AUTHORING_ARGUMENT;
|
|
319
|
+
}
|
|
314
320
|
case 'number': {
|
|
315
321
|
const parsed = Number(unquoteStringLiteral(rawValue));
|
|
316
322
|
return Number.isNaN(parsed) ? INVALID_AUTHORING_ARGUMENT : parsed;
|