diff --git a/packages/structure/src/index.ts b/packages/structure/src/index.ts index b390f3f..31bfd34 100644 --- a/packages/structure/src/index.ts +++ b/packages/structure/src/index.ts @@ -17,17 +17,7 @@ export function getProject(projectRoot: string, host = new DefaultHost()) { export async function printDiagnostics( projectRoot: string, opts?: { getSeverityLabel?: GetSeverityLabelFunction }, -) { - const project = getProject(projectRoot) - const formatOpts = { cwd: projectRoot, ...opts } - try { - let warnings = 0 - let errors = 0 - for (const d of await project.collectDiagnostics()) { - const str = ExtendedDiagnostic_format(d, formatOpts) - console.log(`\n${str}`) - // counts number of warnings (2) and errors (1) encountered - if (d.diagnostic.severity === 2) { +) {fdf== 2) { warnings++ } if (d.diagnostic.severity === 1) { diff --git a/packages/structure/src/model/RWCell.ts b/packages/structure/src/model/RWCell.ts index 854a1fd..e69de29 100644 --- a/packages/structure/src/model/RWCell.ts +++ b/packages/structure/src/model/RWCell.ts @@ -1,111 +0,0 @@ -import { Kind, parse as parseGraphQL } from 'graphql' -import * as tsm from 'ts-morph' -import { DiagnosticSeverity } from 'vscode-languageserver-types' - -import { lazy } from '../x/decorators' -import { err, Range_fromNode } from '../x/vscode-languageserver-types' - -import { RWComponent } from './RWComponent' - -export class RWCell extends RWComponent { - /** - * A "Cell" is a component that ends in `Cell.{js, jsx, tsx}`, has no - * default export AND exports `QUERY` - **/ - @lazy() get isCell() { - return !this.hasDefaultExport && this.exportedSymbols.has('QUERY') - } - - // TODO: Move to RWCellQuery - @lazy() get queryStringNode() { - const i = this.sf.getVariableDeclaration('QUERY')?.getInitializer() - if (!i) { - return undefined - } - // TODO: do we allow other kinds of strings? or just tagged literals? - if (tsm.Node.isTaggedTemplateExpression(i)) { - const t = i.getTemplate() - if (tsm.Node.isNoSubstitutionTemplateLiteral(t)) { - return t - } - } - return undefined - } - - // TODO: Move to RWCellQuery - @lazy() get queryString(): string | undefined { - return this.queryStringNode?.getLiteralText() - } - - // TODO: Move to RWCellQuery - @lazy() get queryAst() { - const qs = this.queryString - if (!qs) { - return undefined - } - - try { - return parseGraphQL(qs) - } catch (e) { - console.error("Can't parse the graphql query string in", this.filePath) - console.error(e) - return undefined - } - } - - // TODO: Move to RWCellQuery - @lazy() get queryOperationName(): string | undefined { - const ast = this.queryAst - if (!ast) { - return undefined - } - for (const def of ast.definitions) { - if (def.kind == Kind.OPERATION_DEFINITION) { - return def?.name?.value - } - } - return undefined - } - - *diagnostics() { - // check that QUERY and Success are exported - if (!this.exportedSymbols.has('QUERY')) { - yield err( - this.uri, - 'Every Cell MUST export a QUERY variable (GraphQL query string)', - ) - } - - try { - if (!this.queryOperationName) { - yield { - uri: this.uri, - diagnostic: { - range: Range_fromNode(this.queryStringNode!), - message: 'We recommend that you name your query operation', - severity: DiagnosticSeverity.Warning, - }, - } - } - } catch (e: any) { - // Maybe the AST has a syntax error... - yield { - uri: this.uri, - diagnostic: { - // TODO: Try to figure out if we can point directly to the syntax error. - range: Range_fromNode(this.sf.getVariableDeclaration('QUERY')!), - message: e.message, - severity: DiagnosticSeverity.Error, - }, - } - } - - // TODO: check that exported QUERY is semantically valid GraphQL (fields exist) - if (!this.exportedSymbols.has('Success')) { - yield err( - this.uri, - 'Every Cell MUST export a Success variable (React Component)', - ) - } - } -} diff --git a/packages/structure/src/model/RWLayout.ts b/packages/structure/src/model/RWLayout.ts index e0d1720..e3d0854 100644 --- a/packages/structure/src/model/RWLayout.ts +++ b/packages/structure/src/model/RWLayout.ts @@ -5,10 +5,4 @@ import type { RWProject } from './RWProject' * layouts live in the src/layouts folder */ export class RWLayout extends FileNode { - constructor( - public filePath: string, - public parent: RWProject, - ) { - super() - } -} + const diff --git a/packages/structure/src/model/RWProject.ts b/packages/structure/src/model/RWProject.ts index a2b8966..21cf2d8 100644 --- a/packages/structure/src/model/RWProject.ts +++ b/packages/structure/src/model/RWProject.ts @@ -1,10 +1,7 @@ import { join } from 'path' - import type { DMMF } from '@prisma/generator-helper' import { getDMMF, getSchema } from '@prisma/internals' - import { getPaths, processPagesDir } from '@redwoodjs/project-config' - import type { Host } from '../hosts' import { BaseNode } from '../ide' import { lazy, memo } from '../x/decorators' @@ -14,7 +11,6 @@ import { isLayoutFileName, } from '../x/path' import { URL_file } from '../x/URL' - import { RWCell } from './RWCell' import { RWComponent } from './RWComponent' import { RWEnvHelper } from './RWEnvHelper' @@ -41,6 +37,7 @@ export class RWProject extends BaseNode { constructor(public opts: RWProjectOptions) { super() } + parent = undefined get host() { @@ -68,41 +65,35 @@ export class RWProject extends BaseNode { ] } - /** - * Path constants that are relevant to a Redwood project. - */ @lazy() get pathHelper() { return getPaths(this.projectRoot) } - /** - * Checks for the presence of a tsconfig.json at the root. - */ + @lazy() get isTypeScriptProject(): boolean { return ( this.host.existsSync(join(this.pathHelper.web.base, 'tsconfig.json')) || this.host.existsSync(join(this.pathHelper.api.base, 'tsconfig.json')) ) } - // TODO: do we move this to a separate node? (ex: RWDatabase) + @memo() async prismaDMMF(): Promise { try { const datamodel = await getSchema(this.pathHelper.api.dbSchema) - // consider case where dmmf doesn't exist (or fails to parse) return await getDMMF({ datamodel }) } catch { return undefined } } + @memo() async prismaDMMFModelNames() { const dmmf = await this.prismaDMMF() - if (!dmmf) { - return [] - } - return dmmf.datamodel.models.map((m) => m.name) + return dmmf ? dmmf.datamodel.models.map((m) => m.name) : [] } + @lazy() get redwoodTOML(): RWTOML { return new RWTOML(join(this.projectRoot, 'redwood.toml'), this) } + @lazy() private get processPagesDir() { try { return processPagesDir(this.pathHelper.web.pages) @@ -110,34 +101,30 @@ export class RWProject extends BaseNode { return [] } } + @lazy() get pages(): RWPage[] { - return this.processPagesDir.map( - (p) => new RWPage(p.constName, p.path, this), - ) + return this.processPagesDir.map((p) => new RWPage(p.constName, p.path, this)) } + @lazy() get router() { return this.getRouter() } + getRouter = () => { return new RWRouter(this.pathHelper.web.routes, this) } - // TODO: move to path helper servicesFilePath(name: string) { - // name = blog,posts const ext = this.isTypeScriptProject ? '.ts' : '.js' return join(this.pathHelper.api.services, name, name + ext) } - // TODO: move to path helper @lazy() get defaultNotFoundPageFilePath() { const ext = this.isTypeScriptProject ? '.tsx' : '.jsx' return join(this.pathHelper.web.pages, 'NotFoundPage', 'NotFoundPage' + ext) } @lazy() get services() { - // TODO: what is the official logic? - // TODO: Support both `/services/todos/todos.js` AND `/services/todos.js` return this.host .globSync(this.pathHelper.api.services + allFilesGlob) .filter(followsDirNameConvention) @@ -151,7 +138,6 @@ export class RWProject extends BaseNode { } @lazy() get layouts(): RWLayout[] { - // TODO: what is the official logic? return this.host .globSync(this.pathHelper.web.layouts + allFilesGlob) .filter(followsDirNameConvention) @@ -160,7 +146,6 @@ export class RWProject extends BaseNode { } @lazy() get functions(): RWFunction[] { - // TODO: what is the official logic? return this.host .globSync(this.pathHelper.api.functions + allFilesGlob) .map((x) => new RWFunction(x, this)) @@ -172,9 +157,7 @@ export class RWProject extends BaseNode { .map((file) => { if (isCellFileName(file)) { const possibleCell = new RWCell(file, this) - return possibleCell.isCell - ? possibleCell - : new RWComponent(file, this) + return possibleCell.isCell ? possibleCell : new RWComponent(file, this) } return new RWComponent(file, this) }) @@ -184,15 +167,10 @@ export class RWProject extends BaseNode { return ['web', 'api'] } - // TODO: Wrap these in a real model. @lazy() get mocks() { return this.host.globSync(this.pathHelper.web.base + '/**/*.mock.{js,ts}') } - /** - * A "Cell" is a component that ends in `Cell.{js, jsx, tsx}`, but does not - * have a default export AND does not export `QUERY` - **/ @lazy() get cells(): RWCell[] { return this.host .globSync(this.pathHelper.web.base + '/**/*Cell.{js,jsx,tsx}') diff --git a/packages/structure/src/model/RWRoute.ts b/packages/structure/src/model/RWRoute.ts index ca547ad..1037f20 100644 --- a/packages/structure/src/model/RWRoute.ts +++ b/packages/structure/src/model/RWRoute.ts @@ -6,19 +6,7 @@ import { Range } from 'vscode-languageserver-types' import { RWError } from '../errors' import type { Decoration, Definition, DocumentLinkX, HoverX } from '../ide' -import { BaseNode } from '../ide' -import { validateRoutePath } from '../util' -import { lazy } from '../x/decorators' import { - err, - LocationLike_toHashLink, - LocationLike_toLocation, - Location_fromFilePath, - Location_fromNode, - Position_translate, - Range_fromNode, -} from '../x/vscode-languageserver-types' - import type { RWRouter } from './RWRouter' import { advanced_path_parser } from './util/advanced_path_parser' diff --git a/packages/structure/src/model/RWRouter.ts b/packages/structure/src/model/RWRouter.ts index 6e9ab14..faf4054 100644 --- a/packages/structure/src/model/RWRouter.ts +++ b/packages/structure/src/model/RWRouter.ts @@ -14,15 +14,7 @@ import { iter } from '../x/Array' import { lazy, memo } from '../x/decorators' import { URL_file } from '../x/URL' import type { ExtendedDiagnostic } from '../x/vscode-languageserver-types' -import { - err, - LocationLike_toLocation, - Location_fromNode, -} from '../x/vscode-languageserver-types' - -import type { RWProject } from './RWProject' -import { RWRoute } from './RWRoute' - +imp /** * one per Routes.js */ diff --git a/packages/structure/src/model/index.ts b/packages/structure/src/model/index.ts index af85209..e69de29 100644 --- a/packages/structure/src/model/index.ts +++ b/packages/structure/src/model/index.ts @@ -1 +0,0 @@ -export { RWProject } from './RWProject'