@roomi-fields/grillhouse 0.0.0-stage → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +9 -0
- package/METACADRE.md +41 -0
- package/agents/developpeur.md +10 -0
- package/agents/explorateur.md +9 -0
- package/agents/questionneur.md +11 -0
- package/agents/referent-technique.md +9 -0
- package/agents/regulateur.md +11 -0
- package/agents/relecteur.md +9 -0
- package/agents/testwriter.md +10 -0
- package/bin/grillhouse.mjs +125 -0
- package/cadre/templates/projet/.claude/settings.json +30 -0
- package/cadre/templates/projet/.editorconfig +47 -0
- package/cadre/templates/projet/.env.example +57 -0
- package/cadre/templates/projet/.eslintrc.cjs +56 -0
- package/cadre/templates/projet/.github/workflows/ci.yml +66 -0
- package/cadre/templates/projet/.mcp.json +13 -0
- package/cadre/templates/projet/.prettierrc +11 -0
- package/cadre/templates/projet/CHANGELOG.md +61 -0
- package/cadre/templates/projet/CLAUDE.md +46 -0
- package/cadre/templates/projet/CONTRIBUTING.md +243 -0
- package/cadre/templates/projet/CREDITS.md +41 -0
- package/cadre/templates/projet/README.md +152 -0
- package/cadre/templates/projet/_gitignore +91 -0
- package/cadre/templates/projet/_npmignore +46 -0
- package/cadre/templates/projet/deployment/README.md +98 -0
- package/cadre/templates/projet/deployment/docs/01-INSTALL.md +145 -0
- package/cadre/templates/projet/deployment/docs/02-CONFIGURATION.md +117 -0
- package/cadre/templates/projet/deployment/docs/03-API.md +264 -0
- package/cadre/templates/projet/deployment/docs/04-TROUBLESHOOTING.md +262 -0
- package/cadre/templates/projet/deployment/scripts/install.ps1 +100 -0
- package/cadre/templates/projet/deployment/scripts/start.ps1 +61 -0
- package/cadre/templates/projet/deployment/scripts/stop.ps1 +37 -0
- package/cadre/templates/projet/deployment/scripts/test.ps1 +118 -0
- package/cadre/templates/projet/docs/agents/issue-tracker.md +44 -0
- package/cadre/templates/projet/ecosystem.config.cjs +73 -0
- package/cadre/templates/projet/package.json +90 -0
- package/cadre/templates/projet/pitmaster/SUIVI.md +22 -0
- package/cadre/templates/projet/src/config.ts +68 -0
- package/cadre/templates/projet/src/errors.ts +102 -0
- package/cadre/templates/projet/src/index.ts +46 -0
- package/cadre/templates/projet/src/services/.gitkeep +8 -0
- package/cadre/templates/projet/src/types/index.ts +24 -0
- package/cadre/templates/projet/src/utils/logger.ts +106 -0
- package/cadre/templates/projet/tests/integration/.gitkeep +7 -0
- package/cadre/templates/projet/tests/unit/config.spec.ts +68 -0
- package/cadre/templates/projet/tests/unit/errors.spec.ts +132 -0
- package/cadre/templates/projet/tests/unit/types.spec.ts +73 -0
- package/cadre/templates/projet/tsconfig.eslint.json +9 -0
- package/cadre/templates/projet/tsconfig.json +41 -0
- package/cadre/templates/projet/tsdoc.json +6 -0
- package/cadre/templates/projet/vitest.config.ts +44 -0
- package/cadre/templates/turbo/paquets.json +29 -0
- package/cadre/templates/turbo/sans-paquets.json +28 -0
- package/charte.md +107 -0
- package/docs/ARCHITECTURE.md +90 -0
- package/hooks/crochet.mjs +33 -0
- package/hooks/hooks.json +58 -0
- package/hooks/register.tsx +558 -0
- package/package.json +75 -4
- package/scripts/avancement.mjs +244 -0
- package/scripts/bilan.mjs +523 -0
- package/scripts/branche-de-nuit.mjs +59 -0
- package/scripts/cadre.mjs +109 -0
- package/scripts/circuit.mjs +4375 -0
- package/scripts/code-mort.mjs +371 -0
- package/scripts/composants-affectes.mjs +598 -0
- package/scripts/consommateurs-arbitres.mjs +192 -0
- package/scripts/consommateurs.mjs +310 -0
- package/scripts/crochet.mjs +24 -0
- package/scripts/crochets.mjs +135 -0
- package/scripts/dernier-vert.mjs +208 -0
- package/scripts/dette.mjs +181 -0
- package/scripts/droits.mjs +354 -0
- package/scripts/enveloppe/codes.mjs +17 -0
- package/scripts/enveloppe/composant.mjs +11 -0
- package/scripts/enveloppe/enveloppe.mjs +628 -0
- package/scripts/enveloppe/lancer.sh +311 -0
- package/scripts/etapes.mjs +323 -0
- package/scripts/etat-du-circuit.mjs +104 -0
- package/scripts/frontieres.mjs +456 -0
- package/scripts/gardes-du-cadre.mjs +72 -0
- package/scripts/greffons.mjs +338 -0
- package/scripts/grillhouse-maj.mjs +514 -0
- package/scripts/index-interfaces.mjs +293 -0
- package/scripts/init.mjs +117 -0
- package/scripts/integration/file-attente.mjs +61 -0
- package/scripts/integration/file.mjs +494 -0
- package/scripts/integration/integrer.mjs +381 -0
- package/scripts/integration/rejeu.mjs +139 -0
- package/scripts/integration/verdict.mjs +13 -0
- package/scripts/interfaces-contre-code.mjs +547 -0
- package/scripts/ligne-etat/defaut.sh +110 -0
- package/scripts/ligne-etat/ligne-etat.mjs +93 -0
- package/scripts/migrations/0.23.0-charte-importee.mjs +47 -0
- package/scripts/migrations/0.23.0-config-vitest.mjs +105 -0
- package/scripts/migrations/0.23.0-crochets-de-seance.mjs +55 -0
- package/scripts/migrations/0.23.0-marche-du-projet.mjs +82 -0
- package/scripts/migrations.mjs +43 -0
- package/scripts/nuit.sh +269 -0
- package/scripts/paquets.mjs +79 -0
- package/scripts/poussee-cles.mjs +46 -0
- package/scripts/preparation.mjs +84 -0
- package/scripts/references-par-les-types.mjs +420 -0
- package/scripts/registre.mjs +336 -0
- package/scripts/resultats.mjs +580 -0
- package/scripts/resumes.mjs +57 -0
- package/scripts/retirer-copie.sh +127 -0
- package/scripts/session-start.sh +203 -0
- package/scripts/sortie.mjs +155 -0
- package/scripts/sous-modules.sh +316 -0
- package/scripts/structure-guard.sh +27 -0
- package/scripts/superviseur.mjs +102 -0
- package/scripts/tableau.mjs +1886 -0
- package/scripts/tests.mjs +236 -0
- package/scripts/ticket.sh +23 -0
- package/scripts/turbo-des-paquets.mjs +899 -0
- package/scripts/un-commit-par-ticket.mjs +212 -0
- package/scripts/verifier.mjs +469 -0
- package/scripts/verrou-de-fichier.mjs +130 -0
- package/scripts/verrou-de-machine.mjs +211 -0
- package/scripts/verrous/commande.mjs +180 -0
- package/scripts/verrous/ticket-du-sous-agent.mjs +39 -0
- package/scripts/verrous/verrou.mjs +165 -0
- package/scripts/vitest-config/avancement.mjs +39 -0
- package/scripts/vitest-config/avancement.reporter.mjs +56 -0
- package/scripts/vitest-config/base-de-passe.mjs +128 -0
- package/scripts/vitest-config/base.d.ts +6 -0
- package/scripts/vitest-config/base.mjs +87 -0
- package/scripts/vitest-config/changements.mjs +173 -0
- package/scripts/vitest-config/cibles.mjs +207 -0
- package/scripts/vitest-config/duree.reporter.mjs +98 -0
- package/scripts/vitest-config/machine.setup.mjs +14 -0
- package/scripts/vitest-config/mesure.d.ts +6 -0
- package/scripts/vitest-config/mesure.mjs +13 -0
- package/scripts/vitest-config/mesure.setup.mjs +12 -0
- package/scripts/vitest-config/pression.mjs +90 -0
- package/scripts/vitest-config/resultats.mjs +23 -0
- package/scripts/vitest-config/resultats.setup.mjs +19 -0
- package/scripts/vitest.nuit.config.mjs +26 -0
- package/skills/developpeur/SKILL.md +175 -0
- package/skills/explorateur/SKILL.md +84 -0
- package/skills/grill/SKILL.md +238 -0
- package/skills/grill/references/releve-structurel.md +38 -0
- package/skills/mesure/SKILL.md +168 -0
- package/skills/pitmaster/SKILL.md +382 -0
- package/skills/pitmaster/references/cadre.md +119 -0
- package/skills/pitmaster/references/consigne-agent.md +308 -0
- package/skills/pitmaster/references/erreurs.md +25 -0
- package/skills/pitmaster/references/tour.md +124 -0
- package/skills/questionneur/SKILL.md +64 -0
- package/skills/redacteur/SKILL.md +84 -0
- package/skills/redacteur/references/documents-d-un-composant.md +105 -0
- package/skills/referent-technique/SKILL.md +145 -0
- package/skills/regulateur/SKILL.md +220 -0
- package/skills/release/SKILL.md +134 -0
- package/skills/release/scripts/update-version.cjs +92 -0
- package/skills/relecteur/SKILL.md +152 -0
- package/skills/relecteur/references/LICENSE-MIT +30 -0
- package/skills/relecteur/references/SOURCE.md +8 -0
- package/skills/relecteur/references/claims-check.md +14 -0
- package/skills/relecteur/references/deletion-check.md +14 -0
- package/skills/relecteur/references/edge-case-hunter.md +80 -0
- package/skills/relecteur/references/verification-gap.md +113 -0
- package/skills/testwriter/SKILL.md +187 -0
- package/types/index.d.ts +56 -0
- package/README.md +0 -3
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
// The references of a ticket's elements found through the types, as « find all references » of
|
|
2
|
+
// rust-analyzer and of TypeScript's language service: an element is resolved as a symbol of the
|
|
3
|
+
// repository's code (a declaration of a package, a member of a type, a function internal to a
|
|
4
|
+
// package), and its references are those the language service resolves to that symbol, never a
|
|
5
|
+
// text that happens to bear its name. scripts/composants-affectes.mjs runs it beside its survey
|
|
6
|
+
// by the names.
|
|
7
|
+
//
|
|
8
|
+
// - The code read is the files of each component's `tsconfig.json` (its `include`), in one
|
|
9
|
+
// language service, so that a reference crosses packages. A workspace package's import resolves
|
|
10
|
+
// to its sources: the target of its `exports` (`.`), read back through its `tsconfig*.json` when
|
|
11
|
+
// it names a built file (`sorties` of scripts/frontieres.mjs), else `src/index.ts`.
|
|
12
|
+
// - An element (`A`, `A.b`, `f()`, `a().b`) resolves, from its last two names, to the member `b`
|
|
13
|
+
// of a type, interface or class `A` declared in a component; else, from its first name, to a
|
|
14
|
+
// declaration of that name at the top of a component's source, else to the members of that
|
|
15
|
+
// name. The test files declare nothing.
|
|
16
|
+
// - A declaration is published when its package's entry exports it (a member, when its type is);
|
|
17
|
+
// its readers are the other components that hold a reference to it, in their production code
|
|
18
|
+
// or their tests: « appel de » for a call, « référence à » otherwise.
|
|
19
|
+
// - An internal declaration has no readers out of its package, as « find all references » starts
|
|
20
|
+
// from a symbol the published interface exports: a word of the ticket that only names it (a word
|
|
21
|
+
// of the language homonym of a private function) leads to no reader.
|
|
22
|
+
// - An element that resolves to several declarations keeps those of the files and the components
|
|
23
|
+
// the ticket names, when it has some, else those of its components. A bare name that only the
|
|
24
|
+
// members of types out of these components bear resolves to none: it names no type.
|
|
25
|
+
import { existsSync } from 'node:fs';
|
|
26
|
+
import { createRequire } from 'node:module';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { lireSiPresent, NOM_DE_TEST } from './consommateurs.mjs';
|
|
29
|
+
import { sorties } from './frontieres.mjs';
|
|
30
|
+
|
|
31
|
+
const requis = createRequire(import.meta.url);
|
|
32
|
+
const DOSSIERS_DE_TEST = new Set(['test', 'tests', '__tests__']);
|
|
33
|
+
const SOURCE_TS = /\.[cm]?tsx?$/;
|
|
34
|
+
const DECLARATION = /\.d\.[cm]?ts$/;
|
|
35
|
+
|
|
36
|
+
// The elements <texte> names between backquotes: [{ ecrit, noms }], `ecrit` its first name,
|
|
37
|
+
// `noms` its names without their calls, in their order, once each.
|
|
38
|
+
export function elementsEcrits(texte) {
|
|
39
|
+
const vus = new Map();
|
|
40
|
+
for (const [, brut] of texte.matchAll(/`([^`\n]+)`/g)) {
|
|
41
|
+
const m = /^([A-Za-z_$][\w$]*)((?:\.[A-Za-z_$][\w$]*|\([^)]*\))*)$/.exec(brut.trim());
|
|
42
|
+
if (!m) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const noms = [
|
|
46
|
+
m[1],
|
|
47
|
+
...[...m[2].replace(/\([^)]*\)/g, '').matchAll(/\.([\w$]+)/g)].map(x => x[1]),
|
|
48
|
+
];
|
|
49
|
+
const cle = noms.join('.');
|
|
50
|
+
if (!vus.has(cle)) {
|
|
51
|
+
vus.set(cle, { ecrit: m[1], noms });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return [...vus.values()];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// The cible strings of an `exports` value, `types` first.
|
|
58
|
+
function cibles(valeur) {
|
|
59
|
+
if (typeof valeur === 'string') {
|
|
60
|
+
return [valeur];
|
|
61
|
+
}
|
|
62
|
+
if (!valeur || typeof valeur !== 'object') {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const cles = Object.keys(valeur).sort((a, b) => (b === 'types') - (a === 'types'));
|
|
66
|
+
return cles.flatMap(k => cibles(valeur[k]));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The source of the subpath <sous> (`.`, `./x`) of the component <c>, or null.
|
|
70
|
+
function entreeDe(c, sous = '.') {
|
|
71
|
+
const pj = JSON.parse(lireSiPresent(path.join(c.dir, 'package.json')) ?? '{}');
|
|
72
|
+
let v = pj.exports;
|
|
73
|
+
const parChemin = v && typeof v === 'object' && Object.keys(v).some(k => k.startsWith('.'));
|
|
74
|
+
if (parChemin) {
|
|
75
|
+
v = v[sous];
|
|
76
|
+
} else if (sous !== '.') {
|
|
77
|
+
v = undefined;
|
|
78
|
+
}
|
|
79
|
+
if (v === undefined && sous === '.') {
|
|
80
|
+
v = pj.types ?? pj.main;
|
|
81
|
+
}
|
|
82
|
+
let emis = null;
|
|
83
|
+
for (const cible of cibles(v)) {
|
|
84
|
+
const abs = path.resolve(c.dir, cible);
|
|
85
|
+
if (SOURCE_TS.test(abs) && !DECLARATION.test(abs) && existsSync(abs)) {
|
|
86
|
+
return abs;
|
|
87
|
+
}
|
|
88
|
+
emis ??= sorties(c.dir);
|
|
89
|
+
const source = [...(emis.get(abs) ?? [])][0];
|
|
90
|
+
if (source) {
|
|
91
|
+
return source;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (sous !== '.') {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return (
|
|
98
|
+
['src/index.ts', 'src/index.tsx', 'index.ts'].map(f => path.join(c.dir, f)).find(existsSync) ??
|
|
99
|
+
null
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const estTest = (c, f) =>
|
|
104
|
+
NOM_DE_TEST.test(path.basename(f)) ||
|
|
105
|
+
path
|
|
106
|
+
.relative(c.dir, f)
|
|
107
|
+
.split(path.sep)
|
|
108
|
+
.some(d => DOSSIERS_DE_TEST.has(d));
|
|
109
|
+
|
|
110
|
+
// The language service over the components <tous> of <racine>: { ts, ls, programme, composantDe }
|
|
111
|
+
// or { raison } when it cannot run.
|
|
112
|
+
function service(ts, racine, tous) {
|
|
113
|
+
const hote = { ...ts.sys, onUnRecoverableConfigFileDiagnostic: () => {} };
|
|
114
|
+
const configs = [];
|
|
115
|
+
for (const c of tous) {
|
|
116
|
+
const f = path.join(c.dir, 'tsconfig.json');
|
|
117
|
+
if (!existsSync(f)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const a = ts.getParsedCommandLineOfConfigFile(f, {}, hote);
|
|
121
|
+
if (a) {
|
|
122
|
+
configs.push(a);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (configs.length === 0) {
|
|
126
|
+
return { raison: 'aucun tsconfig.json dans les composants' };
|
|
127
|
+
}
|
|
128
|
+
const fichiers = [...new Set(configs.flatMap(a => a.fileNames.map(f => path.resolve(f))))];
|
|
129
|
+
const options = {
|
|
130
|
+
...configs[0].options,
|
|
131
|
+
noEmit: true,
|
|
132
|
+
allowJs: true,
|
|
133
|
+
allowImportingTsExtensions: true,
|
|
134
|
+
skipLibCheck: true,
|
|
135
|
+
types: [],
|
|
136
|
+
composite: false,
|
|
137
|
+
incremental: false,
|
|
138
|
+
};
|
|
139
|
+
const entrees = new Map();
|
|
140
|
+
const espace = nom => {
|
|
141
|
+
if (entrees.has(nom)) {
|
|
142
|
+
return entrees.get(nom);
|
|
143
|
+
}
|
|
144
|
+
let r = null;
|
|
145
|
+
for (const c of tous) {
|
|
146
|
+
if (!c.paquet) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (nom === c.paquet) {
|
|
150
|
+
r = entreeDe(c);
|
|
151
|
+
} else if (nom.startsWith(`${c.paquet}/`)) {
|
|
152
|
+
r = entreeDe(c, `.${nom.slice(c.paquet.length)}`);
|
|
153
|
+
}
|
|
154
|
+
if (r) {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
entrees.set(nom, r);
|
|
159
|
+
return r;
|
|
160
|
+
};
|
|
161
|
+
const resolution = {
|
|
162
|
+
fileExists: ts.sys.fileExists,
|
|
163
|
+
readFile: ts.sys.readFile,
|
|
164
|
+
directoryExists: ts.sys.directoryExists,
|
|
165
|
+
getDirectories: ts.sys.getDirectories,
|
|
166
|
+
realpath: ts.sys.realpath,
|
|
167
|
+
};
|
|
168
|
+
const ls = ts.createLanguageService(
|
|
169
|
+
{
|
|
170
|
+
...resolution,
|
|
171
|
+
getScriptFileNames: () => fichiers,
|
|
172
|
+
getScriptVersion: () => '1',
|
|
173
|
+
getScriptSnapshot: f => {
|
|
174
|
+
const t = lireSiPresent(f);
|
|
175
|
+
return t === null ? undefined : ts.ScriptSnapshot.fromString(t);
|
|
176
|
+
},
|
|
177
|
+
getCurrentDirectory: () => racine,
|
|
178
|
+
getCompilationSettings: () => options,
|
|
179
|
+
getDefaultLibFileName: o => ts.getDefaultLibFilePath(o),
|
|
180
|
+
readDirectory: ts.sys.readDirectory,
|
|
181
|
+
resolveModuleNameLiterals: (litteraux, depuis, _redirige, opts) =>
|
|
182
|
+
litteraux.map(l => {
|
|
183
|
+
const source = espace(l.text);
|
|
184
|
+
if (source) {
|
|
185
|
+
return {
|
|
186
|
+
resolvedModule: {
|
|
187
|
+
resolvedFileName: source,
|
|
188
|
+
extension: ts.extensionFromPath(source),
|
|
189
|
+
isExternalLibraryImport: false,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return ts.resolveModuleName(l.text, depuis, opts, resolution);
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
ts.createDocumentRegistry()
|
|
197
|
+
);
|
|
198
|
+
const programme = ls.getProgram();
|
|
199
|
+
const dirs = tous
|
|
200
|
+
.map(c => ({ c, prefixe: c.dir + path.sep }))
|
|
201
|
+
.sort((a, b) => b.prefixe.length - a.prefixe.length);
|
|
202
|
+
const composantDe = f => {
|
|
203
|
+
const abs = path.resolve(f);
|
|
204
|
+
if (abs.split(path.sep).includes('node_modules')) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
return dirs.find(d => abs.startsWith(d.prefixe))?.c ?? null;
|
|
208
|
+
};
|
|
209
|
+
return { ls, programme, composantDe };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// The survey by the types of the elements <ecrits> (`elementsEcrits`) in the components <tous> of
|
|
213
|
+
// <racine>, an element that resolves to several declarations kept to those of the files and the
|
|
214
|
+
// components the ticket names (<contexte>: `{ fichiers, composants }`, Sets of file names and of
|
|
215
|
+
// components), when it has some: `{ etat: 'fait', raison: null, elements: [{ nom, ecrit,
|
|
216
|
+
// declarations: [{ c, publie }], lecteurs: Map component → Set of « par » }] }`, or
|
|
217
|
+
// `{ etat: 'impossible', raison, elements: [] }` when it cannot run.
|
|
218
|
+
export function parLesTypes(racine, tous, ecrits, contexte = {}) {
|
|
219
|
+
try {
|
|
220
|
+
return releveParLesTypes(racine, tous, ecrits, contexte);
|
|
221
|
+
} catch (e) {
|
|
222
|
+
return { etat: 'impossible', raison: `erreur : ${e.message.split('\n')[0]}`, elements: [] };
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function releveParLesTypes(racine, tous, ecrits, { fichiers = new Set(), composants = new Set() }) {
|
|
227
|
+
const ts = requis('typescript');
|
|
228
|
+
const s = service(ts, racine, tous);
|
|
229
|
+
if (s.raison) {
|
|
230
|
+
return { etat: 'impossible', raison: s.raison, elements: [] };
|
|
231
|
+
}
|
|
232
|
+
const { ls, programme, composantDe } = s;
|
|
233
|
+
const checker = programme.getTypeChecker();
|
|
234
|
+
|
|
235
|
+
// The declarations of the components' sources, at their top and as members of their types.
|
|
236
|
+
const hauts = [];
|
|
237
|
+
const membres = [];
|
|
238
|
+
const nomDe = n => (n?.name && ts.isIdentifier(n.name) ? n.name.text : null);
|
|
239
|
+
const ajouterMembres = (haut, liste) => {
|
|
240
|
+
for (const m of liste ?? []) {
|
|
241
|
+
const nom = nomDe(m);
|
|
242
|
+
if (nom) {
|
|
243
|
+
membres.push({ nom, conteneur: haut.nom, noeud: m.name, haut, c: haut.c });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
for (const sf of programme.getSourceFiles()) {
|
|
248
|
+
const c = composantDe(sf.fileName);
|
|
249
|
+
if (!c || estTest(c, sf.fileName) || DECLARATION.test(sf.fileName)) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
for (const st of sf.statements) {
|
|
253
|
+
const decls = ts.isVariableStatement(st)
|
|
254
|
+
? st.declarationList.declarations.filter(d => ts.isIdentifier(d.name))
|
|
255
|
+
: [st];
|
|
256
|
+
for (const d of decls) {
|
|
257
|
+
const nom = nomDe(d);
|
|
258
|
+
if (!nom) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const haut = { nom, conteneur: null, noeud: d.name, c };
|
|
262
|
+
hauts.push(haut);
|
|
263
|
+
if (ts.isClassDeclaration(d) || ts.isInterfaceDeclaration(d)) {
|
|
264
|
+
ajouterMembres(haut, d.members);
|
|
265
|
+
}
|
|
266
|
+
if (ts.isTypeAliasDeclaration(d) && ts.isTypeLiteralNode(d.type)) {
|
|
267
|
+
ajouterMembres(haut, d.type.members);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// The symbols each component's entry exports.
|
|
274
|
+
const exportes = new Map();
|
|
275
|
+
const reel = sym => {
|
|
276
|
+
let x = sym;
|
|
277
|
+
if (x && x.flags & ts.SymbolFlags.Alias) {
|
|
278
|
+
x = checker.getAliasedSymbol(x);
|
|
279
|
+
}
|
|
280
|
+
return x ? checker.getExportSymbolOfSymbol(x) : x;
|
|
281
|
+
};
|
|
282
|
+
const exportsDe = c => {
|
|
283
|
+
if (!exportes.has(c)) {
|
|
284
|
+
const f = entreeDe(c);
|
|
285
|
+
const sf = f ? programme.getSourceFile(f) : undefined;
|
|
286
|
+
const mod = sf ? checker.getSymbolAtLocation(sf) : undefined;
|
|
287
|
+
exportes.set(
|
|
288
|
+
c,
|
|
289
|
+
mod ? checker.getExportsOfModule(mod).map(x => ({ nom: x.name, sym: reel(x) })) : []
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return exportes.get(c);
|
|
293
|
+
};
|
|
294
|
+
const symDe = d => reel(checker.getSymbolAtLocation(d.noeud));
|
|
295
|
+
const publie = d => {
|
|
296
|
+
const h = d.haut ?? d;
|
|
297
|
+
const sym = symDe(h);
|
|
298
|
+
return Boolean(sym) && exportsDe(h.c).some(x => x.sym === sym);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// The references of the declaration <d>: [{ c, appel }], its own declarations left out.
|
|
302
|
+
const noeudA = (sf, pos) => {
|
|
303
|
+
let trouve = null;
|
|
304
|
+
const visiter = n => {
|
|
305
|
+
if (trouve || pos < n.getStart(sf) || pos >= n.getEnd()) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (ts.isIdentifier(n) && n.getStart(sf) === pos) {
|
|
309
|
+
trouve = n;
|
|
310
|
+
} else {
|
|
311
|
+
ts.forEachChild(n, visiter);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
visiter(sf);
|
|
315
|
+
return trouve;
|
|
316
|
+
};
|
|
317
|
+
const estAppel = n => {
|
|
318
|
+
const p = n?.parent;
|
|
319
|
+
if (!p) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
if ((ts.isCallExpression(p) || ts.isNewExpression(p)) && p.expression === n) {
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
return ts.isPropertyAccessExpression(p) && p.name === n && estAppel(p);
|
|
326
|
+
};
|
|
327
|
+
const references = d => {
|
|
328
|
+
const sf = d.noeud.getSourceFile();
|
|
329
|
+
const out = [];
|
|
330
|
+
for (const r of ls.findReferences(sf.fileName, d.noeud.getStart(sf)) ?? []) {
|
|
331
|
+
for (const ref of r.references) {
|
|
332
|
+
if (ref.isDefinition) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const c = composantDe(ref.fileName);
|
|
336
|
+
if (!c) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const rsf = programme.getSourceFile(ref.fileName);
|
|
340
|
+
const n = rsf ? noeudA(rsf, ref.textSpan.start) : null;
|
|
341
|
+
out.push({ c, appel: estAppel(n) });
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
};
|
|
346
|
+
// The declarations an element resolves to: in the files and the components the ticket names,
|
|
347
|
+
// else in its components, else anywhere; at the top before the members. <hors>: for each list,
|
|
348
|
+
// the level at which its declarations resolve to none.
|
|
349
|
+
const dansUnComposant = d => composants.has(d.c);
|
|
350
|
+
const partout = () => true;
|
|
351
|
+
const dansLeFichier = d =>
|
|
352
|
+
composants.has(d.c) && fichiers.has(path.basename(d.noeud.getSourceFile().fileName));
|
|
353
|
+
const choisir = (hors, ...listes) => {
|
|
354
|
+
for (const garder of [dansLeFichier, dansUnComposant, partout]) {
|
|
355
|
+
for (const [i, l] of listes.entries()) {
|
|
356
|
+
const g = l.filter(garder);
|
|
357
|
+
if (g.length) {
|
|
358
|
+
return garder === hors[i] ? [] : g;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return [];
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
const resoudre = ({ noms }) => {
|
|
366
|
+
if (noms.length >= 2) {
|
|
367
|
+
const [conteneur, nom] = noms.slice(-2);
|
|
368
|
+
const m = choisir(
|
|
369
|
+
[],
|
|
370
|
+
membres.filter(x => x.nom === nom && x.conteneur === conteneur)
|
|
371
|
+
);
|
|
372
|
+
if (m.length) {
|
|
373
|
+
return { nom: `${conteneur}.${nom}`, decls: m };
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// A bare member name, out of the components the ticket names, names no member of a known type.
|
|
377
|
+
const decls = choisir(
|
|
378
|
+
[null, partout],
|
|
379
|
+
hauts.filter(x => x.nom === noms[0]),
|
|
380
|
+
membres.filter(x => x.nom === noms[0])
|
|
381
|
+
);
|
|
382
|
+
return { nom: noms[0], decls };
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const elements = [];
|
|
386
|
+
const vus = new Set();
|
|
387
|
+
for (const e of ecrits) {
|
|
388
|
+
const { nom, decls } = resoudre(e);
|
|
389
|
+
if (decls.length === 0 || vus.has(nom)) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
vus.add(nom);
|
|
393
|
+
const lecteurs = new Map();
|
|
394
|
+
const lire = (c, par) => {
|
|
395
|
+
if (!lecteurs.has(c)) {
|
|
396
|
+
lecteurs.set(c, new Set());
|
|
397
|
+
}
|
|
398
|
+
lecteurs.get(c).add(par);
|
|
399
|
+
};
|
|
400
|
+
const declarations = [];
|
|
401
|
+
for (const d of decls) {
|
|
402
|
+
const estPublie = publie(d);
|
|
403
|
+
declarations.push({ c: d.c, publie: estPublie });
|
|
404
|
+
if (!estPublie) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const parComposant = new Map();
|
|
408
|
+
for (const r of references(d)) {
|
|
409
|
+
if (r.c !== d.c) {
|
|
410
|
+
parComposant.set(r.c, parComposant.get(r.c) || r.appel);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
for (const [c, appel] of parComposant) {
|
|
414
|
+
lire(c, `${appel ? 'appel de' : 'référence à'} ${nom}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
elements.push({ nom, ecrit: e.ecrit, declarations, lecteurs });
|
|
418
|
+
}
|
|
419
|
+
return { etat: 'fait', raison: null, elements };
|
|
420
|
+
}
|