From 95dd76c04857107dd49fe5a5b3a1d49b56b09780 Mon Sep 17 00:00:00 2001 From: Zdenek Nemec Date: Thu, 2 Jul 2020 09:34:01 +0200 Subject: [PATCH 1/7] feat: Export Profile AST alongside with Map AST BREAKING CHANGE: `ProfileIdNode` from Map AST is now called `MapProfileIdNode` --- package.json | 4 ++-- src/interfaces/ast/index.ts | 1 + src/interfaces/ast/location.ts | 4 ++++ src/interfaces/ast/map-ast.ts | 13 +++++-------- src/interfaces/ast/map-ast.utils.ts | 8 ++++---- src/interfaces/ast/profile-ast.ts | 15 ++++----------- 6 files changed, 20 insertions(+), 25 deletions(-) create mode 100644 src/interfaces/ast/location.ts diff --git a/package.json b/package.json index 90822ba..1a2f96c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@superindustries/language", - "version": "0.1.4", - "description": "Level 5 autonomous, self-driving API client, https://superface.ai", + "version": "0.2.0", + "description": "Superface profile and map language ASTs, https://superface.ai", "main": "dist/language.js", "source": "src/index.ts", "module": "dist/language.modern.js", diff --git a/src/interfaces/ast/index.ts b/src/interfaces/ast/index.ts index 46a701a..9199480 100644 --- a/src/interfaces/ast/index.ts +++ b/src/interfaces/ast/index.ts @@ -1,2 +1,3 @@ export * from './map-ast'; export * from './map-ast.utils'; +export * from './profile-ast'; diff --git a/src/interfaces/ast/location.ts b/src/interfaces/ast/location.ts new file mode 100644 index 0000000..32dbaf8 --- /dev/null +++ b/src/interfaces/ast/location.ts @@ -0,0 +1,4 @@ +export interface Location { + start: number; + end: number; +} diff --git a/src/interfaces/ast/map-ast.ts b/src/interfaces/ast/map-ast.ts index 1cfe42b..c10e442 100644 --- a/src/interfaces/ast/map-ast.ts +++ b/src/interfaces/ast/map-ast.ts @@ -1,3 +1,5 @@ +import { Location } from './location'; + export type MapNodeKind = | 'EvalDefinition' | 'HTTPOperationDefinition' @@ -16,11 +18,6 @@ export type MapNodeKind = | 'StepDefinition' | 'VariableExpressionsDefinition'; -export interface Location { - start: number; - end: number; -} - export interface MapASTNodeBase { kind: MapNodeKind; loc?: Location; @@ -111,7 +108,7 @@ export interface OperationDefinitionNode extends MapASTNodeBase { stepsDefinition: StepDefinitionNode[]; } -export interface ProfileIdNode extends MapASTNodeBase { +export interface MapProfileIdNode extends MapASTNodeBase { kind: 'ProfileId'; profileId: string; } @@ -123,7 +120,7 @@ export interface ProviderNode extends MapASTNodeBase { export interface MapNode extends MapASTNodeBase { kind: 'Map'; - profileId: ProfileIdNode; + profileId: MapProfileIdNode; provider: ProviderNode; } @@ -154,7 +151,7 @@ export type MapASTNode = | OperationCallDefinitionNode | OperationDefinitionNode | OutcomeDefinitionNode - | ProfileIdNode + | MapProfileIdNode | ProviderNode | StepDefinitionNode | VariableExpressionDefinitionNode; diff --git a/src/interfaces/ast/map-ast.utils.ts b/src/interfaces/ast/map-ast.utils.ts index 251f06c..f2c99d1 100644 --- a/src/interfaces/ast/map-ast.utils.ts +++ b/src/interfaces/ast/map-ast.utils.ts @@ -12,7 +12,7 @@ import { OperationCallDefinitionNode, OperationDefinitionNode, OutcomeDefinitionNode, - ProfileIdNode, + MapProfileIdNode, ProviderNode, StepDefinitionNode, VariableExpressionDefinitionNode, @@ -90,9 +90,9 @@ export function assertIsOperationDefinitionNode( checkNode(node, 'OperationDefinition'); } -export function assertIsProfileIdNode( +export function assertIsMapProfileIdNode( node: MapASTNode -): asserts node is ProfileIdNode { +): asserts node is MapProfileIdNode { checkNode(node, 'ProfileId'); } @@ -182,7 +182,7 @@ export function isOperationDefinitionNode( return node.kind === 'OperationDefinition'; } -export function isProfileIdNode(node: MapASTNode): node is ProfileIdNode { +export function isProfileIdNode(node: MapASTNode): node is MapProfileIdNode { return node.kind === 'ProfileId'; } diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index b32b583..b8a9215 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -1,3 +1,5 @@ +import { Location } from './location'; + export type ScalarTypeName = 'boolean' | 'number' | 'string'; export interface ModelTypeName extends ProfileASTNodeBase { @@ -27,20 +29,11 @@ export type ProfileNodeKind = | 'ModelTypeName' | 'ObjectModelTypeName'; -// TODO: Same as in Map AST -> reuse? -export interface Location { - start: number; - end: number; -} - -// TODO: Similar as in Map AST -> reuse? export interface ProfileASTNodeBase { kind: ProfileNodeKind; loc?: Location; } - -// TODO: Same as in Map AST -> reuse? -export interface ProfileIdNode extends ProfileASTNodeBase { +export interface ProfileProfileIdNode extends ProfileASTNodeBase { kind: 'ProfileId'; profileId: string; } @@ -52,7 +45,7 @@ export interface DocumentedNode { export interface ProfileNode extends ProfileASTNodeBase, DocumentedNode { kind: 'Profile'; - profileId: ProfileIdNode; + profileId: ProfileProfileIdNode; } export interface ProfileDocumentNode extends ProfileASTNodeBase { From 4d85ea7d22c5a3f935150ba8d57834f6888235eb Mon Sep 17 00:00:00 2001 From: Zdenek Nemec Date: Thu, 2 Jul 2020 09:37:08 +0200 Subject: [PATCH 2/7] =?UTF-8?q?chore:=20Order=20imports=20by=20name=20?= =?UTF-8?q?=F0=9F=92=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interfaces/ast/map-ast.utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/ast/map-ast.utils.ts b/src/interfaces/ast/map-ast.utils.ts index f2c99d1..3669543 100644 --- a/src/interfaces/ast/map-ast.utils.ts +++ b/src/interfaces/ast/map-ast.utils.ts @@ -8,11 +8,11 @@ import { MapDocumentNode, MapExpressionDefinitionNode, MapNode, + MapProfileIdNode, NetworkOperationDefinitionNode, OperationCallDefinitionNode, OperationDefinitionNode, OutcomeDefinitionNode, - MapProfileIdNode, ProviderNode, StepDefinitionNode, VariableExpressionDefinitionNode, From 1d3d426a3bea4606466950bb21bbea7eb1102219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Lavu=C5=A1?= Date: Mon, 6 Jul 2020 12:10:06 +0200 Subject: [PATCH 3/7] feat: Restructure and document profile AST BREAKING CHANGE: Made `ScalarTypeName` its own node BREAKING CHANGE: Removed `ObjectModelTypeName` and used `ModelTypeName` everywhere --- src/interfaces/ast/profile-ast.ts | 262 +++++++++++++++++++----------- 1 file changed, 167 insertions(+), 95 deletions(-) diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index b8a9215..1a0abaa 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -1,165 +1,237 @@ import { Location } from './location'; -export type ScalarTypeName = 'boolean' | 'number' | 'string'; - -export interface ModelTypeName extends ProfileASTNodeBase { - kind: 'ModelTypeName'; - name: string; -} - -export interface ObjectModelTypeName extends ProfileASTNodeBase { - kind: 'ObjectModelTypeName'; - name: string; -} +// BASE // export type ProfileNodeKind = - | 'ProfileDocument' - | 'Profile' - | 'ProfileId' - | 'UseCaseDefinition' - | 'FieldDefinition' - | 'ScalarModelDefinition' + // TYPES + | 'ScalarTypeName' | 'ObjectModelDefinition' + | 'FieldDefinition' | 'UnionModelDefinition' | 'EnumModelDefinition' | 'EnumValueDefinition' - | 'NamedType' + | 'ModelTypeName' | 'ListType' | 'NonNullType' - | 'ModelTypeName' - | 'ObjectModelTypeName'; + // MODELS + | 'ScalarModelDefinition' + // USECASE + | 'UseCaseDefinition' + // DOCUMENT + | 'ProfileId' + | 'Profile' + | 'ProfileDocument'; export interface ProfileASTNodeBase { kind: ProfileNodeKind; + /** Corresponds to span in lexer */ loc?: Location; } -export interface ProfileProfileIdNode extends ProfileASTNodeBase { - kind: 'ProfileId'; - profileId: string; -} +/** Node preceded by documenting string literal */ export interface DocumentedNode { title?: string; description?: string; } -export interface ProfileNode extends ProfileASTNodeBase, DocumentedNode { - kind: 'Profile'; - profileId: ProfileProfileIdNode; -} +// TYPES // -export interface ProfileDocumentNode extends ProfileASTNodeBase { - kind: 'ProfileDocument'; - profile: ProfileNode; - definitions: DocumentDefinition[]; +/** From keywords: `Boolean`, `Number` and `String` */ +export interface ScalarTypeName extends ProfileASTNodeBase { + kind: 'ScalarTypeName'; + name: 'boolean' | 'number' | 'string'; } -export enum ProfileUseCaseSafety { - safe = 'safe', - unsafe = 'unsafe', - idempotent = 'idempotent', +/** + * Construct of form: + * `{ fields... }` + */ +export interface ObjectModelDefinitionNode + extends ProfileASTNodeBase, + DocumentedNode { + kind: 'ObjectModelDefinition'; + fields: FieldDefinition[]; +} +/** + * Construct of form: + * `ident: type` or `ident` + * that appear inside object model definitions + */ +export interface FieldDefinition extends ProfileASTNodeBase, DocumentedNode { + kind: 'FieldDefinition'; + fieldName: string; + type?: Type; +} +/** + * Construct of form: + * `type | type | ...` + */ +export interface UnionModelDefinitionNode + extends ProfileASTNodeBase, + DocumentedNode { + kind: 'UnionModelDefinition'; + types: Type[]; +} +/** + * Construct of form: + * `enum { values... }` + */ +export interface EnumModelDefinitionNode + extends ProfileASTNodeBase, + DocumentedNode { + kind: 'EnumModelDefinition'; + enumValues: EnumValueDefinition[]; } +/** + * Variant of an enum definition. + * + * These are either string or number literals + */ +export interface EnumValueDefinition + extends ProfileASTNodeBase, + DocumentedNode { + kind: 'EnumValueDefinition'; + enumValue: string | number; +} +export type AnonymousModelDefinitionNode = + | ObjectModelDefinitionNode + | UnionModelDefinitionNode + | EnumModelDefinitionNode; -export interface NamedType extends ProfileASTNodeBase { - kind: 'NamedType'; - type: ModelTypeName | ScalarTypeName; +/** + * Name of a model type parsed from identifiers. + * + * This is the name of a user defined type. + */ +export interface ModelTypeName extends ProfileASTNodeBase { + kind: 'ModelTypeName'; + name: string; } +/** Array type: `[type]` */ export interface ListType extends ProfileASTNodeBase { kind: 'ListType'; type: Type; } - +/** Non-null assertion operator: `type!` */ export interface NonNullType extends ProfileASTNodeBase { kind: 'NonNullType'; - type: NamedType | ListType | AnonymousModelDefinitionNode; + type: + | ScalarTypeName + | ModelTypeName + | ListType + | AnonymousModelDefinitionNode; } export type Type = - | NamedType + | ScalarTypeName + | AnonymousModelDefinitionNode + | ModelTypeName | ListType - | NonNullType - | AnonymousModelDefinitionNode; - -export interface FieldDefinition extends ProfileASTNodeBase, DocumentedNode { - kind: 'FieldDefinition'; - fieldName: string; - type: Type; - exampleValue?: string; -} + | NonNullType; -export interface ProfileUseCaseDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { - kind: 'UseCaseDefinition'; - useCaseName: string; - safety: ProfileUseCaseSafety; - input?: ObjectModelDefinitionNode | ObjectModelTypeName; - result: ObjectModelDefinitionNode | ObjectModelTypeName; - errors?: ObjectModelTypeName[]; -} +// MODELS // +/** + * Construct of form: + * `field ident: ScalarType` or `field ident: ModelType` + * + * This is basically a type alias. + */ export interface NamedScalarModelDefinitionNode extends ProfileASTNodeBase, DocumentedNode { kind: 'ScalarModelDefinition'; modelName: ModelTypeName; - baseType: ScalarTypeName; -} - -export interface ObjectModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { - kind: 'ObjectModelDefinition'; - fields: FieldDefinition[]; + baseType: ScalarTypeName | ModelTypeName; } +/** + * Construct of form: + * `model ident { fields... }` + */ export interface NamedObjectModelDefinitionNode extends ObjectModelDefinitionNode { - modelName: ObjectModelTypeName; -} - -export interface UnionModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { - kind: 'UnionModelDefinition'; modelName: ModelTypeName; } +/** + * Construct of form: + * `field ident: type | type | ...` + */ export interface NamedUnionModelDefinitionNode extends UnionModelDefinitionNode { modelName: ModelTypeName; } -export interface EnumModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { - kind: 'EnumModelDefinition'; - enumValues: EnumValueDefinition[]; -} - +/** + * Construct of form: + * `enum ident { values ... }` + */ export interface NamedEnumModelDefinitionNode extends EnumModelDefinitionNode { modelName: ModelTypeName; } -export interface EnumValueDefinition - extends ProfileASTNodeBase, - DocumentedNode { - kind: 'EnumValueDefinition'; - enumValue: string | number; -} - -export type AnonymousModelDefinitionNode = - | ObjectModelDefinitionNode - | UnionModelDefinitionNode - | EnumModelDefinitionNode; - export type ProfileModelDefinitionNode = | NamedScalarModelDefinitionNode | NamedObjectModelDefinitionNode | NamedUnionModelDefinitionNode | NamedEnumModelDefinitionNode; +// USECASE // + +/** Usecase safety indicator, corresponds to decorators */ +export enum ProfileUseCaseSafety { + safe = 'safe', + unsafe = 'unsafe', + idempotent = 'idempotent', +} + +/** +* Construct of form: +``` +usecase ident @deco { + input: type + result: type + errors: [ + type + type + ... + ] +} +``` +*/ +export interface ProfileUseCaseDefinitionNode + extends ProfileASTNodeBase, + DocumentedNode { + kind: 'UseCaseDefinition'; + useCaseName: string; + safety: ProfileUseCaseSafety; + input?: Type; + result: Type; + errors?: Type[]; +} + +// DOCUMENT // + +/** `profile: string` */ +export interface ProfileProfileIdNode extends ProfileASTNodeBase { + kind: 'ProfileId'; + profileId: string; +} +/** + * The node containing document information at the top of the document. + */ +export interface ProfileNode extends ProfileASTNodeBase, DocumentedNode { + kind: 'Profile'; + profileId: ProfileProfileIdNode; +} +/** Node enclosing the whole document */ +export interface ProfileDocumentNode extends ProfileASTNodeBase { + kind: 'ProfileDocument'; + profile: ProfileNode; + definitions: DocumentDefinition[]; +} export type DocumentDefinition = | ProfileUseCaseDefinitionNode | ProfileModelDefinitionNode; From f75ba46832e23aa1b7399ecca2f826a97093f4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Lavu=C5=A1?= Date: Mon, 6 Jul 2020 12:37:00 +0200 Subject: [PATCH 4/7] fix: add `asyncResult` field to `ProfileUseCaseDefinitionNode` ast node --- src/interfaces/ast/profile-ast.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index 1a0abaa..ce82417 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -209,6 +209,7 @@ export interface ProfileUseCaseDefinitionNode safety: ProfileUseCaseSafety; input?: Type; result: Type; + asyncResult: boolean; errors?: Type[]; } From 4cd9391553002eb797059dfcc92211651ac1964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Lavu=C5=A1?= Date: Mon, 6 Jul 2020 23:46:10 +0200 Subject: [PATCH 5/7] feat: unify Location and Span terminology with parser BREAKING CHANGE: Renamed Location from ASTs to Span and added new Location type This unifies the terminology between parser and language definition and also extends the information saved in AST nodes. --- src/interfaces/ast/location.ts | 4 ---- src/interfaces/ast/map-ast.ts | 5 +++-- src/interfaces/ast/profile-ast.ts | 6 +++--- src/interfaces/ast/source.ts | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 9 deletions(-) delete mode 100644 src/interfaces/ast/location.ts create mode 100644 src/interfaces/ast/source.ts diff --git a/src/interfaces/ast/location.ts b/src/interfaces/ast/location.ts deleted file mode 100644 index 32dbaf8..0000000 --- a/src/interfaces/ast/location.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Location { - start: number; - end: number; -} diff --git a/src/interfaces/ast/map-ast.ts b/src/interfaces/ast/map-ast.ts index c10e442..5ffb7a8 100644 --- a/src/interfaces/ast/map-ast.ts +++ b/src/interfaces/ast/map-ast.ts @@ -1,4 +1,4 @@ -import { Location } from './location'; +import { Location, Span } from './source'; export type MapNodeKind = | 'EvalDefinition' @@ -20,7 +20,8 @@ export type MapNodeKind = export interface MapASTNodeBase { kind: MapNodeKind; - loc?: Location; + span?: Span; + location?: Location; } export interface JSExpressionNode extends MapASTNodeBase { diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index ce82417..165b99d 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -1,4 +1,4 @@ -import { Location } from './location'; +import { Location, Span } from './source'; // BASE // @@ -24,8 +24,8 @@ export type ProfileNodeKind = export interface ProfileASTNodeBase { kind: ProfileNodeKind; - /** Corresponds to span in lexer */ - loc?: Location; + span?: Span; + location?: Location; } /** Node preceded by documenting string literal */ diff --git a/src/interfaces/ast/source.ts b/src/interfaces/ast/source.ts new file mode 100644 index 0000000..c6183dc --- /dev/null +++ b/src/interfaces/ast/source.ts @@ -0,0 +1,17 @@ +/** + * Human-readable location of a token inside source code. + * + * Both `line` and `column` are indexed from 1. + */ +export type Location = { + line: number; + column: number; +}; + +/** + * Span of one node inside source code. + */ +export type Span = { + start: number; + end: number; +}; \ No newline at end of file From 57b885582a075f11fb43e5752a0b610727f0c060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Lavu=C5=A1?= Date: Tue, 7 Jul 2020 19:49:35 +0200 Subject: [PATCH 6/7] fix: move `extend DocumentedNode` to named nodes --- src/interfaces/ast/profile-ast.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index 165b99d..116b140 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -47,8 +47,7 @@ export interface ScalarTypeName extends ProfileASTNodeBase { * `{ fields... }` */ export interface ObjectModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { + extends ProfileASTNodeBase { kind: 'ObjectModelDefinition'; fields: FieldDefinition[]; } @@ -67,8 +66,7 @@ export interface FieldDefinition extends ProfileASTNodeBase, DocumentedNode { * `type | type | ...` */ export interface UnionModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { + extends ProfileASTNodeBase { kind: 'UnionModelDefinition'; types: Type[]; } @@ -77,8 +75,7 @@ export interface UnionModelDefinitionNode * `enum { values... }` */ export interface EnumModelDefinitionNode - extends ProfileASTNodeBase, - DocumentedNode { + extends ProfileASTNodeBase { kind: 'EnumModelDefinition'; enumValues: EnumValueDefinition[]; } @@ -151,7 +148,7 @@ export interface NamedScalarModelDefinitionNode * `model ident { fields... }` */ export interface NamedObjectModelDefinitionNode - extends ObjectModelDefinitionNode { + extends ObjectModelDefinitionNode, DocumentedNode { modelName: ModelTypeName; } @@ -160,7 +157,7 @@ export interface NamedObjectModelDefinitionNode * `field ident: type | type | ...` */ export interface NamedUnionModelDefinitionNode - extends UnionModelDefinitionNode { + extends UnionModelDefinitionNode, DocumentedNode { modelName: ModelTypeName; } @@ -168,7 +165,7 @@ export interface NamedUnionModelDefinitionNode * Construct of form: * `enum ident { values ... }` */ -export interface NamedEnumModelDefinitionNode extends EnumModelDefinitionNode { +export interface NamedEnumModelDefinitionNode extends EnumModelDefinitionNode, DocumentedNode { modelName: ModelTypeName; } From f7587b9dc6dd7f4a42a2be72bc7437ba84040d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Lavu=C5=A1?= Date: Tue, 7 Jul 2020 20:18:42 +0200 Subject: [PATCH 7/7] fix: EnumValueDefinition cannot be DocumentedNode because both can be strings --- src/interfaces/ast/profile-ast.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/interfaces/ast/profile-ast.ts b/src/interfaces/ast/profile-ast.ts index 116b140..e154322 100644 --- a/src/interfaces/ast/profile-ast.ts +++ b/src/interfaces/ast/profile-ast.ts @@ -84,12 +84,11 @@ export interface EnumModelDefinitionNode * * These are either string or number literals */ -export interface EnumValueDefinition - extends ProfileASTNodeBase, - DocumentedNode { +export interface EnumValueDefinition extends ProfileASTNodeBase { kind: 'EnumValueDefinition'; - enumValue: string | number; + enumValue: string | number | boolean; } + export type AnonymousModelDefinitionNode = | ObjectModelDefinitionNode | UnionModelDefinitionNode