@gouvfr/dsfr-nexus
Version:
Le module `dsfr-nexus` est l'interface de ligne de commande (CLI) centrale du Système de Design de l’État - DSFR. Il offre des outils pour gérer et compiler les ressources du DSFR
238 lines (191 loc) • 6.58 kB
JavaScript
import fs from 'fs';
import { createYAMLFile, log, readYAMLSync } from '@gouvfr/dsfr-forge';
import { DocParser } from './doc/doc-parser.js';
import { PageRank } from '../../../common/constants.js'
import { sortMapItems } from '../../../common/utiliy/sort/map-sorting.js';
import { ComponentParser } from './component/component-parser.js';
import path from 'path';
import { GenerationParser } from './generation/generation-parser.js';
const getPartIndexSrc = (state) => `${state.src}/_part/index.yml`;
class PartParser {
constructor (state, parent) {
this._state = state;
this._parent = parent;
this._ascendants = parent ? [parent, ...parent.ascendants] : [];
this._depth = parent ? parent.depth + 1 : 0;
this._root = parent ? parent.root : this;
this._children = [];
this._descendants = [];
this._has = false;
this._isDraft = false;
this._isDetached = false;
this._isIgnored = false;
this._isAuxiliary = false;
this._map = null;
}
get id () {
return this._id;
}
get has () {
return this._has;
}
get isDraft () {
return this._isDraft;
}
get isDetached () {
return this._isDetached;
}
get isIgnored () {
return this._isIgnored;
}
get isAuxiliary () {
return this._isAuxiliary;
}
get children () {
return this._children;
}
get parent () {
return this._parent;
}
get state () {
return this._state;
}
get ascendants () {
return this._ascendants
}
get depth () {
return this._depth;
}
get root () {
return this._root;
}
get descendants () {
return this._descendants;
}
get doc () {
return this._doc;
}
get map () {
return this._map;
}
get descriptor () {
return Object.assign(this._component?.descriptor ?? {}, ...this._children.map(child => child.descriptor));
}
getPart (id) {
return this.root.id === id ? this.root : this.root.descendants.find(descendant => descendant.id === id);
}
async read () {
const indexSrc = getPartIndexSrc(this._state);
if (!fs.existsSync(indexSrc)) return;
this._index = readYAMLSync(indexSrc);
this._isIgnored = this._index.isIgnored === true;
if (this._isIgnored) return;
this._id = this._index.id;
this._state = this._state.setPart(this._id);
const duplicated = this.root.descendants.filter(part => part.id === this._id)
if (duplicated.length) {
log.error(`Part with id '${this._id}' (${this._state.src}) already exists in [${duplicated.map(part => part.src).join(',')}]`);
return;
}
this._has = true;
this._isDraft = this._index.isDraft === true;
this._isDetached = this._index.isDetached === true;
this._isAuxiliary = this._index.isAuxiliary === true;
await this.readStyle(this._index.style);
await this.readScript(this._index.script);
await this.readComponent(this._index.component);
await this.readGeneration(this._index.generation);
await this.readDoc(this._index.doc);
await this.readChildren();
}
async readStyle (data = {}) {
// Placeholder for future style reading logic
}
async readScript (data = {}) {
// Placeholder for future script reading logic
}
async readComponent (data = {}) {
const componentState = this._state.descend('_part/component');
const component = new ComponentParser(componentState, { ...data, id: this._id });
await component.read();
if (!component.has) return;
this._component = component;
}
async readGeneration (data = {}) {
const generationState = this._state.descend('_part/generation').setDest(`${this._state.src}/_generated`);
const generation = new GenerationParser(generationState, { ...data, id: this._id });
await generation.read();
if (!generation.has) return;
this._generation = generation;
}
async readDoc (data = {}) {
const docState = data.isStatic ? this._state.statify(this._id) : this._state.descend('_part/doc');
const doc = new DocParser(docState, this._parent?.doc, this, this._id, this._isAuxiliary ? PageRank.AUXILIARY : PageRank.PART);
await doc.read();
if (!doc.has) return;
this._doc = doc;
this._map = doc.map;
}
async readChildren () {
const entries = fs.readdirSync(this.state.src, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory() || entry.name.startsWith('_')) continue;
const state = this._state.descend(entry.name);
const childIndexSrc = getPartIndexSrc(state);
if (!fs.existsSync(childIndexSrc)) continue;
const childIndex = readYAMLSync(childIndexSrc);
if (!childIndex || !childIndex.id) {
log.error(`Part index file is malformed or missing 'id' property: ${childIndexSrc}`);
continue;
}
if (childIndex.isIgnored === true) continue;
const childState = state.setPath(path.join(state.path, childIndex.id));
const child = new PartParser(childState, this);
await child.read();
if (!child.has) continue;
this._children.push(child);
this._descendants.push(child, ...child.descendants);
}
const childrenMaps = this._children.filter(child => child.doc).map(child => child.map);
if (childrenMaps.length === 0) return;
if (!this._map) this._map = {};
if (this._map.$?.sort) {
sortMapItems(childrenMaps, this._map.$.sort);
}
childrenMaps.forEach(mapItem => {
this._map[mapItem.$.id] = mapItem;
})
}
async write () {
const data = {
id: this._id,
src: this._state.src,
banner: this._state.banner,
isDraft: this._isDraft,
isDetached: this._isDetached,
parent: this._parent?.id,
children: this._children.map(child => child.id),
ascendants: this._ascendants.map(ascendant => ascendant.id),
depth: this._depth,
descendants: this._descendants.map(descendant => descendant.id)
};
if (this._component) {
data.component = this._component.data;
}
if (this._generation) {
data.generation = this._generation.data;
}
if (this._doc) {
data.doc = this._doc.data;
}
createYAMLFile(this.state.configFile('data.yml'), data);
if (this._component) await this._component.write();
if (this._generation) await this._generation.write();
if (this._doc) await this._doc.write();
for (const child of this._children) await child.write();
}
async describe () {
createYAMLFile(this.state.initial.configFile('components.yml'), this.descriptor);
}
}
export { PartParser };