Skip to content

Instantly share code, notes, and snippets.

@jonschlinkert
Created June 20, 2022 07:22
Show Gist options
  • Save jonschlinkert/55a3f68ad5eb77c4a0b77e24a275f04a to your computer and use it in GitHub Desktop.
Save jonschlinkert/55a3f68ad5eb77c4a0b77e24a275f04a to your computer and use it in GitHub Desktop.

Revisions

  1. jonschlinkert created this gist Jun 20, 2022.
    122 changes: 122 additions & 0 deletions prisma-framents-poc.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    const NEWLINE_REGEX = /\r?\n/;
    const INCLUDE_REGEX = /^(\s*)include\(([A-Z][0-9a-zA-Z]*?)\)/;
    const SECTION_START_REGEX = /^([a-z]+) ([A-Z][0-9a-zA-Z]*?)\s*{/;
    const SECTION_END_REGEX = /(?<=})/;

    class Section {
    type = '';
    name = '';
    leading = [];
    body = [];

    expand(fragments = {}) {
    const body = [this.leading];

    for (let i = 0; i < this.body.length; i++) {
    const line = this.body[i];
    const match = INCLUDE_REGEX.exec(line);

    if (!match) {
    body.push(line);
    continue;
    }

    if (!fragments[match[2]]) {
    throw new SyntaxError('Invalid fragment name: ' + match[2]);
    }

    body.push(...fragments[match[2]].map(f => match[1] + f.trim()));
    }

    return body.join('\n');
    }

    stringify() {
    return [this.leading, ...this.body].join('\n');
    }
    }

    class PreProcessor {
    constructor(source = '', fragments) {
    this.source = source;
    this.sections = [];
    this.fragments = { ...fragments };
    }

    tokenize() {
    for (const chunk of this.source.split(SECTION_END_REGEX)) {
    const lines = chunk.split(NEWLINE_REGEX);
    const section = new Section();
    let prev;

    while (lines.length) {
    const match = SECTION_START_REGEX.exec(lines[0]);

    if (match) {
    section.type = match[1];
    section.name = match[2];
    section.body = lines;
    this.sections.push(section);

    if (section.type === 'fragment' && !this.fragments[section.name]) {
    this.fragments[section.name] = section.body.slice(1, -1);
    }
    break;
    } else if (!(prev === '' && lines[0] === '')) {
    section.leading.push(lines[0]);
    }

    prev = lines[0];
    section.body.push(lines.shift());
    }

    section.leading = section.leading.join('\n');
    }

    return this.sections;
    }

    stringify() {
    return this.sections.map(s => s.stringify()).join('\n');
    }

    expand(fragments = this.fragments) {
    if (!this.sections.length) this.tokenize();
    return this.sections.map(s => s.expand(fragments)).join('\n');
    }
    }

    module.exports = PreProcessor;

    const string = `
    fragment Basics {
    updatedAt DateTime @updatedAt
    createdAt DateTime @default(now())
    }
    //
    // This
    // is a
    // comment
    //
    model User {
    include(Id)
    include(Basics)
    }
    model Task {
    include(Id)
    include(Basics)
    }
    `;

    const preprocessor = new PreProcessor(string, {
    Id: ['id String @id @default(cuid())']
    });

    // const sections = preprocessor.tokenize();
    // console.log(preprocessor);
    // console.log(preprocessor.stringify());
    const expanded = preprocessor.expand();
    console.log(expanded);