-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Describe the user story
I'm a developer working on constraints. There are various problems with the current Prolog syntax:
-
My editor doesn't support it very well. The main VSCode extension doesn't stop crashing unless I install swipl, which I shouldn't have to do since I don't use VSCode otherwise.
-
I don't know which functions are available to me. I can check the online documentation, but I'm a bit lazy and I want to see the documentation directly within my editor. I also want it to let me know if I make a mistake (like passing a string variable to
atom/1, or using unknown predicates). -
I want to compose my predicates, and potentially share them with other developers.
Describe the solution you'd like
Let's first make this clear: we will keep using Prolog. It's proven to be a strong choice so far, especially because of how easily it can be used to query the fact database using yarn constraints query. It's a very powerful tool, and there's no reason to reimplement the wheel.
However, for all its qualities, Prolog is somewhat dated and doesn't benefit from the same tooling support as TypeScript (or even JavaScript). Prettier cannot work on it, typecheckers are mostly non-existing. Even its syntax and APIs are somewhat weird in our world.
Fortunately, I think I have a reasonable solution to this problem: TypeScript constraints. For starter, take a look at the following snippet:
import { t, atom, expect, yarn } from "@yarnpkg/constraints-runtime";
yarn
.enforceWorkspaceDependency(
t.WorkspaceCwd,
t.DependencyName,
t.DependencyRange,
t.DependencyType,
)
.forEach([
yarn.workspaceHasDependency(t.WorkspaceCwd, t.DependencyName, _, t.DependencyType),
yarn.workspaceHasDependency(_, t.DependencyName, t.DependencyRange, t.OtherType),
expect.notEqual(t.DependencyType, `peerDependencies`),
expect.notEqual(t.OtherType, `peerDependencies`),
]);
yarn
.enforceWorkspaceDependency(
t.Workspace,
t.DependencyIdent,
t.DependencyRange,
t.DependencyType,
)
.forEach([
yarn.workspaceHasDependency(t.Workspace, t.DependencyIdent, _, t.DependencyType),
expect.notEqual(t.DependencyType, `peerDependencies`),
yarn.workspaceIdent(t.DependencyCwd, t.DependencyIdent),
yarn.workspaceField(t.DependencyCwd, `version`, t.DependencyVersion),
expect.exists(t.DependencyVersion),
expect.notProvable([
yarn.projectWorkspacesByDescriptor(
t.DependencyIdent,
t.DependencyRange,
t.DependencyCwd,
),
]),
when(expect.equal(t.Type, `peerDependencies`), {
then: [
atom.concat(`^`, t.DependencyVersion, t.WorkspaceRange),
],
otherwise: [
atom.concat(`workspace:^`, t.DependencyVersion, t.WorkspaceRange),
],
}),
]);This is Prolog. But it's TypeScript. And because it's TypeScript, it benefits from all the TS tooling, while still having the powerful Prolog semantics that worked so well. Autocomplete will suggest the right functions, typecheck will ensure that we don't pass invalid parameters to our functions (we could then remove those + / - / ? from the documentation), documentation will be displayed on mouse over...
Even better, the syntax would also make it possible to import symbols from third-party packages! Thereby fixing #469, users only having to import predefined predicates from regular dependencies.
Implementation-wise, a few details:
-
The
tvariable would be a proxy that would accept any name and return it as a variable name. I don't think we can restrict it to upper camelcase symbols, which is the only type problem I can foresee. -
Not sure whether to use
_ornull. Both would work, althoughnullwould avoid us having to export a symbol. -
We would still support the Prolog format, so that even if something isn't possible through the TypeScript syntax, it can still be done using the regular Prolog one.
Describe the drawbacks of your solution
-
I find it quite a bit more verbose than the Prolog version. The IDE support makes it worth it imo.
-
The naysayers will be all "ahah you see that JS was better all along". In fact, they probably stopped reading about two and a half seconds after the title 🙃
Describe alternatives you've considered
We can keep using Prolog. The documentation will have to be improved in either cases, though.
Additional context
cc @bgotink