Repository: gatsbyjs/gatsby
File: packages/gatsby-plugin-page-creator/src/is-valid-collection-path-implementation.ts (TypeScript)

Code before:
// in any way have an incorrect filepath setup for us to predictably use collection
// querying.
//
// Without this, users will can get mystic errors.
export function isValidCollectionPathImplementation(
  filePath: string,
  reporter: Reporter
): boolean {
  const parts = filePath.split(sysPath.sep)
  let passing = false
  let errors = 0

  parts.forEach(part => {
    if (!part.includes(`{`) && !part.includes(`}`)) return

    const model = part.matchAll(/\{([a-zA-Z_]\w*)./g) // Search for word before first dot, e.g. Model
    const field = part.matchAll(/{.*?((?<=\w\.)[^}]*)}/g) // Search for everything after the first dot, e.g. foo__bar (or in invalid case: foo.bar)

    const models = Array.from(model, m => m[1])
    const fields = Array.from(field, f => f[1])

    try {
      if (
        models.length === 0 ||
        fields.length === 0 ||
        models.length !== fields.length
      ) {
        throw new Error(errorMessage(part))
      }
      for (const m of models) {
        assert(m, /^[a-zA-Z_]\w*$/, errorMessage(part)) // Check that Model is https://spec.graphql.org/draft/#sec-Names
      }
      for (const f of fields) {
        assert(f, /^[a-zA-Z_][\w_()]*$/, errorMessage(part)) // Check that field is foo__bar__baz (and not foo.bar.baz) + https://spec.graphql.org/draft/#sec-Names
      }
    } catch (e) {
      reporter.panicOnBuild({
        id: prefixId(CODES.CollectionPath),
        context: {
          sourceMessage: e.message,
        },
        filePath: filePath,
      })
      errors++
    }
  })

  if (errors === 0) {
    passing = true
  }


Review comment (suggestion):
This is a check for the case of `{Model.id}-{Model_foo}`.

`models.length` will be 2, `fields.length` will be 1.

With `{Model.id}-{Model.foo}` (valid) it both will be 2

Code after:
// This file is a helper for consumers. It's going to log an error to them if they
// in any way have an incorrect filepath setup for us to predictably use collection
// querying.
//
// Without this, users will can get mystic errors.
export function isValidCollectionPathImplementation(
  filePath: string,
  reporter: Reporter
): boolean {
  const parts = filePath.split(sysPath.sep)
  let passing = false
  let errors = 0

  parts.forEach(part => {
    if (!part.includes(`{`) && !part.includes(`}`)) return

    const model = matchAllPolyfill(/\{([a-zA-Z_]\w*)./g, part) // Search for word before first dot, e.g. Model
    const field = matchAllPolyfill(/.*?((?<=\w\.)[^}]*)}/g, part) // Search for everything after the first dot, e.g. foo__bar (or in invalid case: foo.bar)

    try {
      if (
        model.length === 0 ||
        field.length === 0 ||
        model.length !== field.length
      ) {
        throw new Error(errorMessage(part))
      }

      const models = Array.from(model, m => m[1])
      const fields = Array.from(field, f => f[1])

      for (const m of models) {
        assert(m, /^[a-zA-Z_]\w*$/, errorMessage(part)) // Check that Model is https://spec.graphql.org/draft/#sec-Names
      }
      for (const f of fields) {
        assert(f, /^[a-zA-Z_][\w_()]*$/, errorMessage(part)) // Check that field is foo__bar__baz (and not foo.bar.baz) + https://spec.graphql.org/draft/#sec-Names
      }
    } catch (e) {
      reporter.panicOnBuild({
        id: prefixId(CODES.CollectionPath),
        context: {
          sourceMessage: e.message,
        },
        filePath: filePath,
      })
      errors++
    }
  })

  if (errors === 0) {
    passing = true