From 287140db94d52678d29fd8d4b87c6e6f2360b783 Mon Sep 17 00:00:00 2001
From: CicadaCinema <52425971+CicadaCinema@users.noreply.github.com>
Date: Fri, 8 Sep 2023 15:52:35 +0100
Subject: [PATCH] add "Top-level member list" feature proposal
---
api_analysis/lib/r4/shape-format.md | 224 +++++++++++++++++++++++++++-
1 file changed, 219 insertions(+), 5 deletions(-)
diff --git a/api_analysis/lib/r4/shape-format.md b/api_analysis/lib/r4/shape-format.md
index 4d367723..e4445ce5 100644
--- a/api_analysis/lib/r4/shape-format.md
+++ b/api_analysis/lib/r4/shape-format.md
@@ -1,6 +1,6 @@
# Proposal for package shape format
-Idea:
+## Idea
* Use lists of stuff, let the index in the list act as an ID number. Then we
can just reference the ID number when we reference the thing.
* Include:
@@ -11,10 +11,224 @@ Idea:
* Exclude:
* Return types and argument types (maybe we add this later?)
-Undecided: (added in draft 2)
- * Imports
- * "extends" and "mixin"
- * "implements"
+## Undecided
+### Imports
+See draft 1 -> draft 2.
+
+### `extends` and `mixin`
+See draft 1 -> draft 2.
+
+### `implements`
+See draft 1 -> draft 2.
+
+### Top-level member list
+We could collect all the member shapes (defined across all libraries), and store them all together in one list. We could then refer to the members exported in a given library by their indexes in this list.
+
+This can also allow us to no longer store `.identifiers` of shapes defined and exported in the same package, but note that we still need to record identifiers of any exported external top-level members, since we cannot produce summaries of them.
+
+#### Example
+
+In this example, we encode the member index as a tuple, where the first element is 0 if the member being exported has been defined in this package, and 1 if it is an external member.
+
+Alternatively, we can use one integer as an index, rolling over the count from `.members` into `.externalIdentifiers` (for example, in this case, the index of "Bar" would be 1, because `.members` contains 1 element).
+
+
+Full example
+
+```js
+{
+ "verison": 1,
+ "package": "foo",
+ "version": "1.0.0",
+ // Shapes of top-level members defined in any library in this package.
+ "members": [
+ // This is the 0th top-level member defined in this package.
+ {
+ "name": "Foo",
+ "kind": "class",
+ "members": [
+ {
+ "name": "sayHello",
+ "kind": "method",
+ "params": [
+ {
+ "name": ...,
+ "kind": "positional" | "named",
+ "required": true | false,
+ },
+ ...
+ ],
+ },
+ ...
+ ],
+ },
+ ...
+ ],
+ // Identifiers of top-level members which are defined in a different package,
+ // but exported in this one.
+ "externalIdentifiers": [
+ // This is the 0th external top-level member.
+ "Bar"
+ ],
+ "libraries": [
+ // library 0:
+ {
+ "uri": "package:foo/foo.dart",
+ // Propogated exports, with this we can easily compute the set of exported
+ // members.
+ "exports": [
+ {
+ "library": 1, // library 1 is "package:foo/src/bar.dart"
+ "show": [
+ [1, 0], // the 0th external member is "Bar"
+ ],
+ },
+ {
+ "library": 2, // library 2 is "package:bar/bar.dart"
+ "hide": [
+ [0, 0], // the 0th member defined in this package is "Foo"
+ ],
+ }
+ ],
+ },
+ // library 1:
+ {
+ "uri": "package:foo/src/bar.dart",
+ "exports": [
+ {
+ "id": 0, // library 0 is "package:foo/foo.dart"
+ "hide": [
+ [0, 0], // the 0th member defined in this package is "Foo"
+ ],
+ },
+ ],
+ },
+ // library 2:
+ {
+ // TODO: Is this a good way to do external libraries?
+ "uri": "package:bar/bar.dart",
+ // We know nothing about external libraries, so there no data here.
+ // We have an entry in "libraries" such that they have an identifier.
+ },
+ ],
+}
+```
+
+
+
+Diff from draft 1
+
+```diff
+ {
+ "verison": 1,
+ "package": "foo",
+ "version": "1.0.0",
+- "identifiers": [
+- "Foo", // 0
+- "sayHello", // 1
+- "Bar", // 2
++ // Shapes of top-level members defined in any library in this package.
++ "members": [
++ // This is the 0th top-level member defined in this package.
++ {
++ "name": "Foo",
++ "kind": "class",
++ "members": [
++ {
++ "name": "sayHello",
++ "kind": "method",
++ "params": [
++ {
++ "name": ...,
++ "kind": "positional" | "named",
++ "required": true | false,
++ },
++ ...
++ ],
++ },
++ ...
++ ],
++ },
++ ...
++ ],
++ // Identifiers of top-level members which are defined in a different package,
++ // but exported in this one.
++ "externalIdentifiers": [
++ // This is the 0th external top-level member.
++ "Bar"
+ ],
+ "libraries": [
+ // library 0:
+ {
+ "uri": "package:foo/foo.dart",
+ // Propogated exports, with this we can easily compute the set of exported
+ // members.
+ "exports": [
+ {
+ "library": 1, // library 1 is "package:foo/src/bar.dart"
+- "show": [
+- 2, // identifier 2 is "Bar"
++ "show": [
++ [1, 0], // the 0th external member is "Bar"
+ ],
+ },
+ {
+ "library": 2, // library 2 is "package:bar/bar.dart"
+ "hide": [
+- 0, // identifier 0 is "Foo"
++ [0, 0], // the 0th member defined in this package is "Foo"
+ ],
+ }
+ ],
+- // Top-level things defined in the library
+- // Not everything exported, this can be easily computed by using the
+- // "exports" maps.
+- "members": [
+- {
+- "name": 0 // identifier 0 is "Foo"
+- "kind": "class",
+- "members": [
+- {
+- "name": 1, // identifier 1 is "sayHello"
+- "kind": "method",
+- "params": [
+- {
+- "name": ...,
+- "kind": "positional" | "named",
+- "required": true | false,
+- },
+- ...
+- ],
+- },
+- ...
+- ],
+- },
+- ],
+ },
+ // library 1:
+ {
+ "uri": "package:foo/src/bar.dart",
+ "exports": [
+ {
+ "id": 0, // library 0 is "package:foo/foo.dart"
+ "hide": [
+- 0, // identifier 0 is "Foo"
++ [0, 0], // the 0th member defined in this package is "Foo"
+ ],
+ },
+ ],
+ },
+ // library 2:
+ {
+ // TODO: Is this a good way to do external libraries?
+ "uri": "package:bar/bar.dart",
+ // We know nothing about external libraries, so there no data here.
+ // We have an entry in "libraries" such that they have an identifier.
+ },
+ ],
+ }
+```
+
## Draft 1