fireschema icon indicating copy to clipboard operation
fireschema copied to clipboard

ts-morph raises an exception when running the sample schema

Open katsuya opened this issue 3 years ago • 1 comments

Thanks for the nice tool! When I run the sample schema, An exception is being thrown in the visitor that handles the AST. I tried to investigate, but I couldn't isolate if it was a setup problem or if it was originally not working. If you know anything about it, please let me know.

Error is as follows:

$ npx fireschema schema.ts
For some reason the top parent was not a source file.
$ ./node_modules/fireschema/dist/bin/cli.js schema.ts
/home/katsuya/fireschema_test/node_modules/ts-morph/dist/ts-morph.js:19177
            throw new common.errors.NotImplementedError("For some reason the top parent was not a source file.");
                  ^
NotImplementedError: For some reason the top parent was not a source file.
    at getSourceFileFromNode (/home/katsuya/fireschema_test/node_modules/ts-morph/dist/ts-morph.js:19177:19)
    at getSourceFileNode (/home/katsuya/fireschema_test/node_modules/ts-morph/dist/ts-morph.js:19166:76)
    at Object.createWrappedNode (/home/katsuya/fireschema_test/node_modules/ts-morph/dist/ts-morph.js:19163:76)
    at visitNode (/home/katsuya/fireschema_test/node_modules/fireschema/dist/_transformer/main.js:65:35)
    at visitNodeAndChildren (/home/katsuya/fireschema_test/node_modules/fireschema/dist/_transformer/main.js:36:57)
    at /home/katsuya/fireschema_test/node_modules/fireschema/dist/_transformer/main.js:36:98
    at visitNode (/home/katsuya/fireschema_test/node_modules/typescript/lib/typescript.js:85158:23)
    at Object.visitEachChild (/home/katsuya/fireschema_test/node_modules/typescript/lib/typescript.js:85538:59)
    at visitNodeAndChildren (/home/katsuya/fireschema_test/node_modules/fireschema/dist/_transformer/main.js:36:42)
    at /home/katsuya/fireschema_test/node_modules/fireschema/dist/_transformer/main.js:36:98
[1]    3497853 exit 1     ./node_modules/fireschema/dist/bin/cli.js schema.ts

It occurs in the following steps:

$ mkdir fireschema_test
$ cd fireschema_test
$ cat <<"EOF" > package.json
{
  "name": "fireschema_test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/pubsub": "^2.17.0",
    "@tsconfig/recommended": "^1.0.1",
    "firebase": "^8.3.11",
    "firebase-admin": "^9.11.1",
    "firebase-functions": "^3.15.5",
    "fireschema": "^4.0.4",
    "react": "^17.0.2",
    "ts-node": "^10.2.1",
    "ttypescript": "^1.5.12",
    "typescript": "^4.4.2"
  }
}
EOF
$ cat <<"EOF" > tsconfig.json
{
  "extends": "@tsconfig/recommended/tsconfig.json",
  "compilerOptions": {
    "plugins": [
      {
        "transform": "fireschema/transformer"
      }
    ]
  },
  "include": ["*.ts"]
}
EOF
$ node -v
v14.17.4
$ npm -v
7.21.1
$ npx fireschema schema.ts
For some reason the top parent was not a source file.

The sample schema is as follows:

import { Merge } from 'type-fest'
import {
  $allow,
  $collectionGroups,
  $collectionSchema,
  $docLabel,
  $functions,
  $or,
  $schema,
  createFirestoreSchema,
  FTypes,
} from 'fireschema'

// user
export type User = {
  name: string
  displayName: string | null
  age: number
  timestamp: FTypes.Timestamp
  options: { a: boolean } | undefined
}
export type UserDecoded = Merge<User, { timestamp: Date }>

const UserSchema = $collectionSchema<User, UserDecoded>()({
  decoder: (data) => ({
    ...data,
    timestamp: data.timestamp.toDate(),
  }),
})

// post
type PostA = {
  type: 'a'
  tags: { id: number; name: string }[]
  text: string
}
type PostB = {
  type: 'b'
  tags: { id: number; name: string }[]
  texts: string[]
}
const PostSchema = $collectionSchema<PostA | PostB>()({
  selectors: (q) => ({
    byTag: (tag: string) => q.where('tags', 'array-contains', tag),
  }),
})

export const firestoreSchema = createFirestoreSchema({
  [$functions]: {
    // whether /admins/<uid> exists
    ['isAdmin()']: `
      return exists(/databases/$(database)/documents/admins/$(request.auth.uid));
    `,

    // whether uid matches
    ['matchesUser(uid)']: `
      return request.auth.uid == uid;
    `,
  },

  [$collectionGroups]: {
    posts: {
      [$docLabel]: 'postId',
      [$schema]: PostSchema,
      [$allow]: {
        read: true,
      },
    },
  },

  // /users/{uid}
  users: {
    [$docLabel]: 'uid', // {uid}
    [$schema]: UserSchema, // collectionSchema
    [$allow]: {
      // access control
      read: true, // all user
      write: $or(['matchesUser(uid)', 'isAdmin()']), // only users matching {uid} or admins
    },

    // /users/{uid}/posts/{postId}
    posts: {
      [$docLabel]: 'postId',
      [$schema]: PostSchema,
      [$allow]: {
        read: true,
        write: 'matchesUser(uid)',
      },
    },
  },
})

katsuya avatar Sep 08 '21 05:09 katsuya

Thanks for the report!

I tried changing TypeScript version to 4.2, and it worked fine.

Compiling with custom transformer often causes errors due to version compatibility between typescript and ts-morph, so we will not use custom transformer in v5 or later.

https://github.com/yarnaimo/fireschema/tree/v5

You can try it with npm i -S fireschema@next .

yarnaimo avatar Sep 08 '21 16:09 yarnaimo