Skip to content

Commit

Permalink
tech(fmt/psl): prep-work for further language-server support (#4933)
Browse files Browse the repository at this point in the history
add documentation helper to Top
add name helper to FieldType
Added more positions:
  ModelPosition::Name
  FieldPosition::{Name,Type}
  SourcePosition::Name
  GeneratorPosition
  CompositeTypePosition
split out find_at_position
added find_at_position doc

Added topwalker
some clean-up of publicity
added indexing for generatorid on schema ast
  • Loading branch information
Druue authored Jun 24, 2024
1 parent 293bb8f commit 34ace0e
Show file tree
Hide file tree
Showing 26 changed files with 728 additions and 368 deletions.
9 changes: 6 additions & 3 deletions prisma-fmt/src/code_actions/relation_mode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use lsp_types::{CodeAction, CodeActionKind, CodeActionOrCommand};
use psl::{parser_database::walkers::CompleteInlineRelationWalker, schema_ast::ast::SourceConfig};
use psl::{
parser_database::walkers::CompleteInlineRelationWalker,
schema_ast::ast::{SourceConfig, WithIdentifier, WithName},
};

use super::CodeActionsContext;

Expand All @@ -8,7 +11,7 @@ pub(crate) fn edit_referential_integrity(
context: &CodeActionsContext<'_>,
source: &SourceConfig,
) {
let prop = match source.properties.iter().find(|p| p.name.name == "referentialIntegrity") {
let prop = match source.properties.iter().find(|p| p.name() == "referentialIntegrity") {
Some(prop) => prop,
None => return,
};
Expand All @@ -21,7 +24,7 @@ pub(crate) fn edit_referential_integrity(
context.initiating_file_source(),
"relationMode".to_owned(),
false,
prop.name.span,
prop.identifier().span,
) else {
return;
};
Expand Down
33 changes: 16 additions & 17 deletions psl/parser-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,26 +168,16 @@ impl ParserDatabase {
&self.asts.0.first().unwrap().2
}

/// Iterate all parsed ASTs.
pub fn iter_asts(&self) -> impl Iterator<Item = &ast::SchemaAst> {
self.asts.iter().map(|(_, _, _, ast)| ast)
}

/// Returns file id by name
pub fn file_id(&self, file_name: &str) -> Option<FileId> {
self.asts
.iter()
.find_map(|(file_id, name, _, _)| if name == file_name { Some(file_id) } else { None })
}

/// Iterate all parsed ASTs, consuming parser database
pub fn into_iter_asts(self) -> impl Iterator<Item = ast::SchemaAst> {
self.asts.into_iter().map(|(_, _, _, ast)| ast)
}

/// Iterate all file ids
pub fn iter_file_ids(&self) -> impl Iterator<Item = FileId> + '_ {
self.asts.iter().map(|(file_id, _, _, _)| file_id)
/// The name of the file.
pub fn file_name(&self, file_id: FileId) -> &str {
self.asts[file_id].0.as_str()
}

/// A parsed AST.
Expand Down Expand Up @@ -223,6 +213,16 @@ impl ParserDatabase {
self.asts[file_id].1.as_str()
}

/// Iterate all parsed ASTs, consuming parser database
pub fn into_iter_asts(self) -> impl Iterator<Item = ast::SchemaAst> {
self.asts.into_iter().map(|(_, _, _, ast)| ast)
}

/// Iterate all parsed ASTs.
pub fn iter_asts(&self) -> impl Iterator<Item = &ast::SchemaAst> {
self.asts.iter().map(|(_, _, _, ast)| ast)
}

/// Iterate all source file contents.
pub fn iter_sources(&self) -> impl Iterator<Item = &str> {
self.asts.iter().map(|ast| ast.2.as_str())
Expand All @@ -233,11 +233,10 @@ impl ParserDatabase {
self.asts.iter().map(|ast| (ast.1.as_str(), ast.2))
}

/// The name of the file.
pub fn file_name(&self, file_id: FileId) -> &str {
self.asts[file_id].0.as_str()
/// Iterate all file ids
pub fn iter_file_ids(&self) -> impl Iterator<Item = FileId> + '_ {
self.asts.iter().map(|(file_id, _, _, _)| file_id)
}

/// Iterate all datasources defined in the schema
pub fn datasources(&self) -> impl Iterator<Item = &SourceConfig> {
self.iter_asts().flat_map(|ast| ast.sources())
Expand Down
10 changes: 5 additions & 5 deletions psl/parser-database/src/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) {
let namespace = match (top_id, top) {
(_, ast::Top::Enum(ast_enum)) => {
tmp_names.clear();
validate_identifier(&ast_enum.name, "Enum", ctx);
validate_identifier(ast_enum.identifier(), "Enum", ctx);
validate_enum_name(ast_enum, ctx.diagnostics);
validate_attribute_identifiers(ast_enum, ctx);

Expand All @@ -51,7 +51,7 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) {

if !tmp_names.insert(&value.name.name) {
ctx.push_error(DatamodelError::new_duplicate_enum_value_error(
&ast_enum.name.name,
ast_enum.name(),
&value.name.name,
value.span,
))
Expand Down Expand Up @@ -186,11 +186,11 @@ fn check_for_duplicate_properties<'a>(
) {
tmp_names.clear();
for arg in props {
if !tmp_names.insert(&arg.name.name) {
if !tmp_names.insert(arg.name()) {
ctx.push_error(DatamodelError::new_duplicate_config_key_error(
&format!("{} \"{}\"", top.get_type(), top.name()),
&arg.name.name,
arg.name.span,
arg.name(),
arg.identifier().span,
));
}
}
Expand Down
2 changes: 1 addition & 1 deletion psl/parser-database/src/names/reserved_model_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub(crate) fn validate_model_name(ast_model: &ast::Model, block_type: &'static s
}

pub(crate) fn validate_enum_name(ast_enum: &ast::Enum, diagnostics: &mut Diagnostics) {
if !is_reserved_type_name(&ast_enum.name.name) {
if !is_reserved_type_name(ast_enum.name()) {
return;
}

Expand Down
18 changes: 18 additions & 0 deletions psl/parser-database/src/walkers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod model;
mod relation;
mod relation_field;
mod scalar_field;
mod top;

pub use crate::types::RelationFieldId;
pub use composite_type::*;
Expand All @@ -26,6 +27,7 @@ pub use relation::*;
pub use relation_field::*;
pub use scalar_field::*;
use schema_ast::ast::{NewlineType, WithSpan};
pub use top::*;

use crate::{ast, FileId};

Expand Down Expand Up @@ -66,12 +68,22 @@ pub(crate) fn newline(source: &str, span: Span) -> NewlineType {
}

impl crate::ParserDatabase {
/// Iterate all top level blocks.
fn iter_tops(&self) -> impl Iterator<Item = (FileId, ast::TopId, &ast::Top)> + '_ {
self.asts
.iter()
.flat_map(move |(file_id, _, _, ast)| ast.iter_tops().map(move |(top_id, top)| (file_id, top_id, top)))
}

/// Intern any top by name.
pub fn find_top<'db>(&'db self, name: &str) -> Option<TopWalker<'db>> {
self.interner
.lookup(name)
.and_then(|name_id| self.names.tops.get(&name_id))
.map(|(file_id, top_id)| (*file_id, *top_id))
.map(|(file_id, top_id)| self.walk((file_id, top_id)))
}

/// Find an enum by name.
pub fn find_enum<'db>(&'db self, name: &str) -> Option<EnumWalker<'db>> {
self.interner
Expand Down Expand Up @@ -104,6 +116,12 @@ impl crate::ParserDatabase {
Walker { db: self, id }
}

/// Walk all tops in the schema.
pub fn walk_tops(&self) -> impl Iterator<Item = TopWalker<'_>> {
self.iter_tops()
.map(move |(file_id, top_id, _)| self.walk((file_id, top_id)))
}

/// Walk all enums in the schema.
pub fn walk_enums(&self) -> impl Iterator<Item = EnumWalker<'_>> {
self.iter_tops()
Expand Down
4 changes: 2 additions & 2 deletions psl/parser-database/src/walkers/enum.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
ast::{self, IndentationType, NewlineType, WithDocumentation},
ast::{self, IndentationType, NewlineType, WithDocumentation, WithName},
types,
walkers::{newline, Walker},
};
Expand All @@ -16,7 +16,7 @@ impl<'db> EnumWalker<'db> {

/// The name of the enum.
pub fn name(self) -> &'db str {
&self.ast_enum().name.name
self.ast_enum().name()
}

/// The AST node.
Expand Down
2 changes: 1 addition & 1 deletion psl/parser-database/src/walkers/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
};

/// A `model` declaration in the Prisma schema.
pub type ModelWalker<'db> = super::Walker<'db, (FileId, ast::ModelId)>;
pub type ModelWalker<'db> = super::Walker<'db, crate::ModelId>;

impl<'db> ModelWalker<'db> {
/// The name of the model.
Expand Down
29 changes: 29 additions & 0 deletions psl/parser-database/src/walkers/top.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::{
ast::{self, WithSpan},
FileId,
};

/// Any top declaration in the Prisma schema.
pub type TopWalker<'db> = super::Walker<'db, crate::TopId>;

impl<'db> TopWalker<'db> {
/// The name of the model.
pub fn name(self) -> &'db str {
self.ast_top().name()
}

/// The ID of the file containing the model.
pub fn file_id(self) -> FileId {
self.id.0
}

/// Is the model defined in a specific file?
pub fn is_defined_in_file(self, file_id: FileId) -> bool {
self.ast_top().span().file_id == file_id
}

/// The AST node.
pub fn ast_top(self) -> &'db ast::Top {
&self.db.asts[self.id]
}
}
10 changes: 5 additions & 5 deletions psl/psl-core/src/validate/datasource_loader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
ast::{self, SourceConfig, Span},
ast::{self, SourceConfig, Span, WithName},
configuration::StringFromEnvVar,
datamodel_connector::RelationMode,
diagnostics::{DatamodelError, Diagnostics},
Expand Down Expand Up @@ -40,7 +40,7 @@ pub(crate) fn load_datasources_from_ast(
for src in ast_schema.sources() {
diagnostics.push_error(DatamodelError::new_source_validation_error(
"You defined more than one datasource. This is not allowed yet because support for multiple databases has not been implemented yet.",
&src.name.name,
src.name(),
src.span,
));
}
Expand All @@ -54,15 +54,15 @@ fn lift_datasource(
diagnostics: &mut Diagnostics,
connectors: crate::ConnectorRegistry<'_>,
) -> Option<Datasource> {
let source_name = ast_source.name.name.as_str();
let source_name = ast_source.name();
let mut args: HashMap<_, (_, &Expression)> = ast_source
.properties
.iter()
.map(|arg| match &arg.value {
Some(expr) => Some((arg.name.name.as_str(), (arg.span, expr))),
Some(expr) => Some((arg.name(), (arg.span, expr))),
None => {
diagnostics.push_error(DatamodelError::new_config_property_missing_value_error(
&arg.name.name,
arg.name(),
source_name,
"datasource",
ast_source.span,
Expand Down
11 changes: 6 additions & 5 deletions psl/psl-core/src/validate/generator_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use parser_database::{
ast::{self, Expression, WithDocumentation},
coerce, coerce_array,
};
use schema_ast::ast::WithName;
use std::collections::HashMap;

const PROVIDER_KEY: &str = "provider";
Expand Down Expand Up @@ -39,10 +40,10 @@ fn lift_generator(ast_generator: &ast::GeneratorConfig, diagnostics: &mut Diagno
.properties
.iter()
.map(|arg| match &arg.value {
Some(expr) => Some((arg.name.name.as_str(), expr)),
Some(expr) => Some((arg.name(), expr)),
None => {
diagnostics.push_error(DatamodelError::new_config_property_missing_value_error(
arg.name.name.as_str(),
arg.name(),
generator_name,
"generator",
ast_generator.span,
Expand Down Expand Up @@ -94,7 +95,7 @@ fn lift_generator(ast_generator: &ast::GeneratorConfig, diagnostics: &mut Diagno
.map(|(arr, span)| parse_and_validate_preview_features(arr, &ALL_PREVIEW_FEATURES, span, diagnostics));

for prop in &ast_generator.properties {
let is_first_class_prop = FIRST_CLASS_PROPERTIES.iter().any(|k| *k == prop.name.name);
let is_first_class_prop = FIRST_CLASS_PROPERTIES.iter().any(|k| *k == prop.name());
if is_first_class_prop {
continue;
}
Expand All @@ -103,7 +104,7 @@ fn lift_generator(ast_generator: &ast::GeneratorConfig, diagnostics: &mut Diagno
Some(val) => GeneratorConfigValue::from(val),
None => {
diagnostics.push_error(DatamodelError::new_config_property_missing_value_error(
&prop.name.name,
prop.name(),
generator_name,
"generator",
prop.span,
Expand All @@ -112,7 +113,7 @@ fn lift_generator(ast_generator: &ast::GeneratorConfig, diagnostics: &mut Diagno
}
};

properties.insert(prop.name.name.clone(), value);
properties.insert(prop.name().to_owned(), value);
}

Some(Generator {
Expand Down
8 changes: 8 additions & 0 deletions psl/schema-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ impl std::ops::Index<EnumId> for SchemaAst {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GeneratorId(u32);

impl std::ops::Index<GeneratorId> for SchemaAst {
type Output = GeneratorConfig;

fn index(&self, index: GeneratorId) -> &Self::Output {
self.tops[index.0 as usize].as_generator().unwrap()
}
}

/// An opaque identifier for a datasource block in a schema AST.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SourceId(u32);
Expand Down
10 changes: 9 additions & 1 deletion psl/schema-ast/src/ast/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::ast::{Expression, Identifier, Span, WithSpan};

use super::WithIdentifier;

/// A named property in a config block.
///
/// ```ignore
Expand All @@ -18,7 +20,7 @@ pub struct ConfigBlockProperty {
/// ^^^
/// }
/// ```
pub name: Identifier,
pub(crate) name: Identifier,
/// The property value.
///
/// ```ignore
Expand All @@ -37,3 +39,9 @@ impl WithSpan for ConfigBlockProperty {
self.span
}
}

impl WithIdentifier for ConfigBlockProperty {
fn identifier(&self) -> &Identifier {
&self.name
}
}
2 changes: 1 addition & 1 deletion psl/schema-ast/src/ast/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct Enum {
/// enum Foo { ... }
/// ^^^
/// ```
pub name: Identifier,
pub(crate) name: Identifier,
/// The values of the enum.
///
/// ```ignore
Expand Down
7 changes: 7 additions & 0 deletions psl/schema-ast/src/ast/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ impl FieldType {
}
}

pub fn name(&self) -> &str {
match self {
FieldType::Supported(supported) => &supported.name,
FieldType::Unsupported(name, _) => name,
}
}

pub fn as_unsupported(&self) -> Option<(&str, &Span)> {
match self {
FieldType::Unsupported(name, span) => Some((name, span)),
Expand Down
Loading

0 comments on commit 34ace0e

Please sign in to comment.