5htp 0.0.2

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.
Files changed (35) hide show
  1. package/package.json +94 -0
  2. package/src/commands/build.ts +32 -0
  3. package/src/commands/deploy/app.ts +29 -0
  4. package/src/commands/deploy/web.ts +62 -0
  5. package/src/commands/dev.ts +100 -0
  6. package/src/compiler/client/identite.ts +70 -0
  7. package/src/compiler/client/index.ts +335 -0
  8. package/src/compiler/common/babel/index.ts +261 -0
  9. package/src/compiler/common/babel/plugins/form.ts +191 -0
  10. package/src/compiler/common/babel/plugins/icones-svg.ts +350 -0
  11. package/src/compiler/common/babel/plugins/importations.ts +337 -0
  12. package/src/compiler/common/babel/plugins/injection-dependances/index.ts +223 -0
  13. package/src/compiler/common/babel/plugins/injection-dependances/remplacerFonction.ts +226 -0
  14. package/src/compiler/common/babel/plugins/models.ts +241 -0
  15. package/src/compiler/common/babel/plugins/pages.ts +185 -0
  16. package/src/compiler/common/babel/plugins/queries/index.ts +166 -0
  17. package/src/compiler/common/files/autres.ts +37 -0
  18. package/src/compiler/common/files/images.ts +19 -0
  19. package/src/compiler/common/files/style.ts +64 -0
  20. package/src/compiler/common/index.ts +148 -0
  21. package/src/compiler/common/plugins/indexage/_utils/Stringify.ts +72 -0
  22. package/src/compiler/common/plugins/indexage/_utils/annotations.ts +88 -0
  23. package/src/compiler/common/plugins/indexage/_utils/iterateur.ts +52 -0
  24. package/src/compiler/common/plugins/indexage/icones-svg/index.ts +198 -0
  25. package/src/compiler/common/plugins/indexage/index.ts +132 -0
  26. package/src/compiler/common/plugins/indexage/indexeur.ts +13 -0
  27. package/src/compiler/common/plugins/indexage/injection-dependances/index.ts +68 -0
  28. package/src/compiler/index.ts +86 -0
  29. package/src/compiler/server/index.ts +177 -0
  30. package/src/index.ts +192 -0
  31. package/src/paths.ts +158 -0
  32. package/src/print.ts +12 -0
  33. package/src/utils/index.ts +22 -0
  34. package/src/utils/keyboard.ts +78 -0
  35. package/tsconfig.json +38 -0
@@ -0,0 +1,166 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import path from 'path';
7
+ import { PluginObj } from '@babel/core';
8
+ import * as types from '@babel/types'
9
+
10
+ /*----------------------------------
11
+ - REGEX
12
+ ----------------------------------*/
13
+ const cheminClasseQuery = '@serveur/database/jsql/query/runner';
14
+
15
+ const regFichierModele = /^[a-z]+\/serveur\/modeles\//i;
16
+
17
+ /*----------------------------------
18
+ - WEBPACK RULE
19
+ ----------------------------------*/
20
+ module.exports = {// /serveur/**.ts */
21
+ test: /\/serveur\/(.*)\.(ts)$/i,
22
+ plugins: [
23
+ [Plugin]
24
+ ]
25
+ }
26
+
27
+
28
+ /*----------------------------------
29
+ - PLUGIN
30
+ ----------------------------------*/
31
+ function Plugin (babel) {
32
+
33
+ const t = babel.types as typeof types;
34
+
35
+ const plugin: PluginObj<{
36
+ fichier: string,
37
+ dossier: string
38
+ }> = {
39
+ pre(state) {
40
+
41
+ const { filename, root } = state.opts;
42
+
43
+ if (!filename)
44
+ throw new Error(`Impossible d'obtenir le chemin du fichier actuellement rraité par le plugin`);
45
+
46
+ if (!root)
47
+ throw new Error(`Impossible d'obtenir le chemin de la racine du projet`);
48
+
49
+ this.fichier = filename;
50
+
51
+ const prefixeRoot = root + '/src/'
52
+ this.dossier = path.dirname(filename).substring(prefixeRoot.length)
53
+ },
54
+ visitor: {
55
+ ImportDeclaration(instruction) {
56
+
57
+ if (!(
58
+ instruction.node.specifiers.length === 1
59
+ &&
60
+ instruction.node.specifiers[0].type === 'ImportDefaultSpecifier'
61
+ ))
62
+ return;
63
+
64
+ const cheminImportFichier = instruction.node.source.value;
65
+ const importDefault = instruction.node.specifiers[0];
66
+
67
+ /* Recherche de:
68
+ import PublicScope from './Public/index.sql';
69
+ */
70
+ if (
71
+ // Suffise SQL = déjà traité, ou intention de garder le SQL
72
+ !importDefault.local.name.endsWith('SQL')
73
+ &&
74
+ cheminImportFichier.endsWith('.sql')
75
+ ) {
76
+
77
+ // Extraction des infos
78
+ const nomVarScope = importDefault.local.name;
79
+ const nomImportSql = nomVarScope + 'SQL';
80
+ const cheminCompletImport = path.join(this.dossier, cheminImportFichier);
81
+
82
+ // Génère un ID unique basé sur le chemin
83
+ let cheminScope: string = cheminCompletImport;
84
+ const isModelScope = regFichierModele.test(cheminCompletImport);
85
+ if (isModelScope) {
86
+ // Mission.Public
87
+ const nomModele = path.basename(this.dossier);
88
+ cheminScope = nomModele + '.' + cheminCompletImport.substring(
89
+ this.dossier.length + 1, // +1 pour le dernier slash
90
+ )
91
+ }
92
+
93
+ cheminScope = cheminScope
94
+ .substring(0, cheminScope.length - 4) // Vire l'extension .sql
95
+ .replace(/\//g, '.');
96
+
97
+ if (cheminScope.endsWith('.index'))
98
+ cheminScope = cheminScope.substring(0, cheminScope.length - 6)
99
+
100
+ // Renommage de l'import du sql et instanciaiton de la query
101
+ // NOTE: On ne skip pas, puisque les imports ont été suffixés de SQL
102
+ //instruction.skip();
103
+ let remplacement = []
104
+
105
+ /* Création factory */
106
+ remplacement.push(
107
+
108
+ // + import PublicScopeSql from './Public/index.sql';
109
+ t.importDeclaration(
110
+ [t.importDefaultSpecifier(t.identifier(nomImportSql))],
111
+ t.stringLiteral(cheminImportFichier)
112
+ ),
113
+
114
+ // + const PublicScope = new String( PublicScopeSql );
115
+ t.variableDeclaration('const', [
116
+ t.variableDeclarator(
117
+ t.identifier(nomVarScope),
118
+ t.newExpression(
119
+ t.identifier('String'),
120
+ [t.identifier(nomImportSql)]
121
+ )
122
+ )
123
+ ]),
124
+
125
+ // + PublicScope.id = 'earn/missions/Mission/Public/index';
126
+ t.expressionStatement(
127
+ t.assignmentExpression(
128
+ '=',
129
+ t.memberExpression(
130
+ t.identifier( nomVarScope ),
131
+ t.identifier('id')
132
+ ),
133
+ t.stringLiteral(cheminScope)
134
+ )
135
+ ),
136
+
137
+ // + PublicScope.sourceFile = 'earn/missions/Mission/Public/index.sql'
138
+ t.expressionStatement(
139
+ t.assignmentExpression(
140
+ '=',
141
+ t.memberExpression(
142
+ t.identifier( nomVarScope ),
143
+ t.identifier('sourceFile')
144
+ ),
145
+ t.stringLiteral(cheminCompletImport)
146
+ )
147
+ ),
148
+ )
149
+
150
+ /*console.log(`[babel][plugin][queries]`,
151
+ this.fichier, cheminCompletImport, '\n',
152
+ recast.print( t.program(remplacement) ).code,
153
+ cheminScope
154
+ );*/
155
+
156
+ // Remplacement
157
+ instruction.replaceWithMultiple(remplacement);
158
+
159
+ }
160
+
161
+ }
162
+ }
163
+ };
164
+
165
+ return plugin;
166
+ }
@@ -0,0 +1,37 @@
1
+ import { staticAssetName } from '../../../paths';
2
+
3
+ module.exports = (dev: boolean, client: boolean) => ([
4
+
5
+ // Allow to use ?raw at the end of the module path to iport the raw content only
6
+ // Example: import VisualParserSource from './Parsers/visual.js?raw';
7
+ {
8
+ resourceQuery: /raw/,
9
+ type: 'asset/source',
10
+ },
11
+
12
+ // Client uniquement: Retourne le fichier correspondant au fichier dans le dossier public
13
+ {
14
+ test: /\.(xml|ico|wav|mp3)$/,
15
+ //loader: 'file-loader',
16
+ type: 'asset/resource',
17
+ generator: {
18
+ filename: staticAssetName
19
+ }
20
+ },
21
+
22
+ // Texte brut
23
+ {
24
+ type: 'asset/source',
25
+ test: /\.(md|hbs|sql|txt|csv)$/,
26
+ },
27
+
28
+ // Polices dans un fichier distinc dans le dossier dédié
29
+ {
30
+ test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
31
+ //loader: 'file-loader',
32
+ type: 'asset/resource',
33
+ generator: {
34
+ filename: 'fonts/[name].[ext]'
35
+ }
36
+ }
37
+ ])
@@ -0,0 +1,19 @@
1
+ import { staticAssetName } from '../../../paths';
2
+ import type webpack from 'webpack';
3
+
4
+ module.exports = (dev: boolean, client: boolean): webpack.RuleSetRule[] => {
5
+
6
+ return [{
7
+ test: /\.(bmp|gif|jpg|jpeg|png|ico|svg)$/,
8
+ type: 'asset',
9
+ parser: {
10
+ dataUrlCondition: {
11
+ // https://webpack.js.org/guides/asset-modules/#general-asset-type
12
+ // < 4kb = importation inline
13
+ // > 4kb = référence à l'url
14
+ maxSize: 4 * 1024 // 4kb
15
+ }
16
+ }
17
+
18
+ }]
19
+ }
@@ -0,0 +1,64 @@
1
+ // Plugons
2
+ import MiniCssExtractPlugin from "mini-css-extract-plugin";
3
+ import lessToJs from 'less-vars-to-js';
4
+
5
+ import fs from 'fs-extra';
6
+ import cli from '@cli';
7
+
8
+ module.exports = (dev: Boolean, client: boolean) => {
9
+
10
+ const paletteLess = fs.readFileSync( cli.paths.app.src + '/client/assets/theme.less', 'utf8');
11
+ const themeVars = lessToJs(paletteLess, { resolveVariables: true, stripPrefix: true });
12
+
13
+ return [
14
+
15
+ // Apply PostCSS plugins including autoprefixer
16
+ {
17
+ loader: MiniCssExtractPlugin.loader
18
+ },
19
+
20
+ // Process external/third-party styles
21
+ {
22
+ exclude: [/*process.env.framework + '/kernel', */cli.paths.app.src],
23
+ loader: 'css-loader',
24
+ options: {
25
+ sourceMap: dev
26
+ },
27
+ },
28
+
29
+ // Process internal/project styles (from src folder)
30
+ {
31
+ include: [/*process.env.framework + '/kernel', */cli.paths.app.src],
32
+ loader: 'css-loader',
33
+ options: {
34
+ // CSS Loader https://github.com/webpack/css-loader
35
+ importLoaders: 1,
36
+ sourceMap: dev
37
+ },
38
+ },
39
+
40
+ {
41
+ test: /\.less$/,
42
+ loader: 'less-loader',
43
+ options: {
44
+ lessOptions: {
45
+ // RAPPEL: Rallonge considéralement le temps de compilation
46
+ // Pour math.random
47
+ //javascriptEnabled: true
48
+
49
+ // Défault = parens-division depuis 4.0.0
50
+ // https://lesscss.org/usage/#less-options-math
51
+ math: 'always',
52
+
53
+ globalVars: themeVars
54
+ },
55
+ }
56
+ },
57
+
58
+ /*{
59
+ test: /\.scss/,
60
+ loader: process.env.framework + '/node_modules/sass-loader',
61
+ }*/
62
+ ]
63
+
64
+ }
@@ -0,0 +1,148 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // npm
6
+ import webpack from 'webpack';
7
+ import dayjs from 'dayjs';
8
+
9
+ // Plugins
10
+ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
11
+ import PluginIndexage from './plugins/indexage';
12
+ import IconesSvg from './plugins/indexage/icones-svg';
13
+ import InjectDeps from './plugins/indexage/injection-dependances';
14
+
15
+ // Core
16
+ import { TAppSide } from '@cli';
17
+ import cli from '../..';
18
+
19
+ /*----------------------------------
20
+ - CONSTANTS
21
+ ----------------------------------*/
22
+
23
+ export const regex = {
24
+ scripts: /\.(ts|tsx)$/,
25
+ style: /\.(css|less|scss)$/,
26
+ images: /\.(bmp|gif|jpg|jpeg|png|ico|svg)$/, // SVG gérés par SVGR
27
+ fonts: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
28
+ staticAssetName: /*isDebug ? '[name].[ext].[hash:8]' :*/ '[hash:8][ext]',
29
+ }
30
+
31
+ /*----------------------------------
32
+ - TYPES
33
+ ----------------------------------*/
34
+
35
+ export type TCompileMode = 'dev' | 'prod'
36
+
37
+ /*----------------------------------
38
+ - BASE CONFIG
39
+ ----------------------------------*/
40
+
41
+ export default function createCommonConfig( side: TAppSide, mode: TCompileMode ): webpack.Configuration {
42
+
43
+ const dev = mode === 'dev';
44
+ const config: webpack.Configuration = {
45
+
46
+ // Project root
47
+ context: cli.paths.app.root,
48
+
49
+ mode: dev ? 'development' : 'production',
50
+
51
+ resolveLoader: {
52
+ // Recherche des loaders dans framework/node_modules (psinon, webpack cherche dans le projet)
53
+ modules: [
54
+ cli.paths.core.root + '/node_modules'
55
+ ],
56
+ mainFields: ['loader', 'main'],
57
+ },
58
+
59
+ plugins: [
60
+
61
+ // https://webpack.js.org/plugins/define-plugin/
62
+ new webpack.DefinePlugin({
63
+
64
+ __DEV__: dev,
65
+ SERVER: side === 'server',
66
+ BUILD_DATE: JSON.stringify(dayjs().format('YY.MM.DD-HH.mm')),
67
+
68
+ CORE_PATH: JSON.stringify(cli.paths.core.root),
69
+ APP_PATH: JSON.stringify(cli.paths.app.root),
70
+ APP_NAME: JSON.stringify(cli.identity.web.title),
71
+
72
+ }),
73
+
74
+ new PluginIndexage(side === 'client' ? {
75
+ 'icones-svg': new IconesSvg,
76
+ } : {
77
+ //'injection-dependances': new InjectDeps,
78
+ }),
79
+
80
+ ...(cli.args.analyze === side ? [
81
+
82
+ new BundleAnalyzerPlugin({
83
+ defaultSizes: 'stat',
84
+ openAnalyzer: false
85
+ }),
86
+
87
+ ] : []),
88
+
89
+
90
+
91
+ ...(dev ? [
92
+
93
+ // HMR
94
+ //new webpack.HotModuleReplacementPlugin()
95
+
96
+ ] : []),
97
+
98
+ ],
99
+
100
+ resolve: {
101
+
102
+ // Empêche le remplatcement des chemins vers les liens symboliques par leur vrai chemin
103
+ // Permet de conserver le chemin des packages enregistrés via npm link
104
+ // Equivalent tsconfig: preserveSymlinks: true
105
+ symlinks: false,
106
+
107
+ /*modules: [
108
+ cli.paths.core.root + '/node_modules',
109
+ cli.paths.app.root + '/node_modules',
110
+ ]*/
111
+ },
112
+
113
+ // Turn off performance processing because we utilize
114
+ // our own hints via the FileSizeReporter
115
+ performance: false,
116
+
117
+ // Don't attempt to continue if there are any errors.
118
+ bail: !dev,
119
+
120
+ // When true, Can cause troubles on re-compiling the client side
121
+ // "webpack" The "path" argument must be of type string. Received undefined
122
+ // https://github.com/webpack/webpack/issues/12616
123
+ // Update: Hum it's fixed, just had to update webpack deps
124
+ cache: dev,
125
+
126
+ profile: true,
127
+
128
+ // Pour bundle-stats
129
+ // https://github.com/relative-ci/bundle-stats/tree/master/packages/cli#webpack-configuration
130
+ stats: {
131
+ cached: dev,
132
+ cachedAssets: dev,
133
+ chunks: dev,
134
+ chunkModules: dev,
135
+ colors: true,
136
+ hash: dev,
137
+ modules: dev,
138
+ reasons: dev,
139
+ timings: true,
140
+ version: dev,
141
+ errorDetails: true
142
+ },
143
+
144
+ }
145
+
146
+ return config;
147
+
148
+ }
@@ -0,0 +1,72 @@
1
+ const placeholder: string = '____PLACEHOLDER____';
2
+ const balises = {
3
+ fonction: '[fonction]',
4
+ methode: '[methode]'
5
+ }
6
+
7
+ const regRemplacements = new RegExp('("([^"]+)": )?"' + placeholder + '"', 'g');
8
+
9
+ // Permet de transformer un objet en chaine json sans niquer les fonctions
10
+ export default ( obj: object, fonctions: string[] = [] ): string => {
11
+
12
+ var fns: [string, string][] = [];
13
+
14
+ // Remplace les fonctions par un placeholder et tranforme en json
15
+ var json = JSON.stringify(obj, (key: string, value: any): string => {
16
+
17
+ const func: boolean = typeof value === 'function';
18
+ const ref_fonction: boolean = typeof value === 'string' && value.startsWith( balises.fonction );
19
+ const ref_methode: boolean = typeof value === 'string' && value.startsWith( balises.methode );
20
+
21
+ if (fonctions.includes(key) || func || ref_fonction || ref_methode) {
22
+
23
+ if (func)
24
+ value = value.toString();
25
+ else if (ref_fonction)
26
+ value = value.substring( balises.fonction.length );
27
+ else if (ref_methode)
28
+ value = value.substring( balises.methode.length );
29
+
30
+ fns.push([ value, ref_methode ? 'methode' : 'fonction' ]);
31
+
32
+ return placeholder;
33
+ }
34
+
35
+ return value;
36
+ }, 4);
37
+
38
+ // Remplace les placeholders par la fonction brute sans les guillemets
39
+ json = json.replace(regRemplacements, (match: string, contnom: string, nom: string): string => {
40
+ const func = fns.shift();
41
+ if (Array.isArray(func)) {
42
+
43
+ const [ fonction, type ] = func;
44
+
45
+ // La fonction est dans un tableau
46
+ if (nom === undefined)
47
+ return fonction;
48
+ else
49
+ return type === 'methode'
50
+ // nom() { ... }
51
+ ? nom + fonction
52
+ // "nom": () => { ... }
53
+ : '"'+ nom +'": ' + fonction;
54
+
55
+ return fonction ? fonction : '';
56
+
57
+ } else
58
+ return '';
59
+ });
60
+
61
+ // retire les quotes
62
+ json = json.replace(/\"([a-zA-Z]+)\"\:/gm, '$1:');
63
+
64
+ // Correction pour les méthodes de classe
65
+ // Remplace <nom>: <args> => { par <nom><args> {
66
+ json = json.replace(
67
+ /([a-zA-Z]+)\:\s*(\([a-zA-Z\,\s]*\))\s*\=\>\s*\{/gmi,
68
+ '$1$2 {'
69
+ );
70
+
71
+ return json;
72
+ };
@@ -0,0 +1,88 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+ import fs from 'fs-extra';
5
+
6
+ /*----------------------------------
7
+ - TYPE
8
+ ----------------------------------*/
9
+ type TDonnees = {[cle: string]: string | number};
10
+
11
+ /*----------------------------------
12
+ - FONCTION
13
+ ----------------------------------*/
14
+ export default function lireAnnotations<TRetour = TDonnees>( fichier: string ): TRetour | undefined {
15
+
16
+ let annotations: TRetour = {} as TRetour;
17
+ let lectureAnnotations: boolean = false;
18
+
19
+ // Lecture de chaque ligne
20
+ const lignes = fs.readFileSync(fichier, 'utf-8').split('\n');
21
+ for (let ligne of lignes) {
22
+
23
+ // Debut des annotations
24
+ if (ligne === "/* ~~~~~~~~~~~~~~~~") {
25
+
26
+ lectureAnnotations = true;
27
+
28
+ // Fin des anotations
29
+ } else if (ligne === "~~~~~~~~~~~~~~~~ */") {
30
+
31
+ return annotations;
32
+
33
+ // Lecture des annotations
34
+ } else if (lectureAnnotations) {
35
+
36
+ // Retire le "* " au debut de la ligne
37
+ ligne = ligne.substring(2).trim();
38
+ // Ligne vide
39
+ if (ligne.length === 0)
40
+ continue;
41
+
42
+ // Niveau indentation
43
+ //const indentation = ligne.match(/^( )*/)
44
+ //const indentLevel = indentation === null ? 0 : indentation[0].length;
45
+
46
+ // cle: valeur
47
+ if (ligne.includes(': ')) {
48
+
49
+ // Décomposition clé / valeur
50
+ let [cle, valeur] = ligne.split(': ') as [string, any];
51
+ cle = cle.trim().toLowerCase();
52
+
53
+ // retire le commentaire
54
+ const poscommentaire = valeur.indexOf(' //')
55
+ if (poscommentaire !== -1)
56
+ valeur = valeur.substring(0, poscommentaire);
57
+ valeur = valeur.trim();
58
+
59
+ // Met en minuscules
60
+ if (cle) {
61
+
62
+ // Correction type valeur
63
+ if (valeur === 'true')
64
+ valeur = true;
65
+ else if (valeur === 'false')
66
+ valeur = false;
67
+ else if (!isNaN(Number(valeur)))
68
+ valeur = parseFloat(valeur);
69
+
70
+ // Référencement
71
+ if (annotations[cle] === undefined)
72
+ annotations[cle] = valeur;
73
+ // Valeur déjà existante, regroupement dans un tableau
74
+ else if (!Array.isArray(annotations[cle]))
75
+ annotations[cle] = [annotations[cle], valeur];
76
+ // Déjà en tableau, ajout élement
77
+ else
78
+ annotations[cle] = [...annotations[cle], valeur];
79
+
80
+ }
81
+
82
+ }
83
+ }
84
+
85
+ }
86
+
87
+ return undefined;
88
+ }
@@ -0,0 +1,52 @@
1
+ const path = require('path')
2
+ const fs = require('fs')
3
+
4
+ export default function iterateur(
5
+ dir: string,
6
+ func: (fichier: string, ext: string, cheminRelatif: string, dossier: string) => void,
7
+ extensions: string[] = [],
8
+ blacklist: string[] = [],
9
+ func_sinon?: (fichier: string) => void,
10
+ dir_root?: string
11
+ ) {
12
+
13
+ if (dir_root === undefined)
14
+ dir_root = dir;
15
+
16
+ // Lecture du contenu du dossier
17
+ const elements = fs.readdirSync(dir);
18
+ for (const file of elements) {
19
+
20
+ const file_relatif = dir + '/' + file;
21
+
22
+ // Pas dans la blacklist
23
+ if ((!blacklist || !blacklist.includes( file ))) {
24
+
25
+ // Récup chemin complet
26
+ const file_complet = path.resolve(dir, file);
27
+
28
+ // Extension sans le point
29
+ const ext = path.extname( file ).substring(1);
30
+
31
+ // Recup infos element
32
+ const stat = fs.statSync(file_complet);
33
+
34
+ // Dossier = recursion
35
+ if (stat && stat.isDirectory())
36
+
37
+ iterateur( file_relatif, func, extensions, blacklist, func_sinon, dir_root );
38
+
39
+ else if (extensions.includes( ext )) {
40
+
41
+ let chemin = file_relatif.substring(dir_root.length + 1, file_relatif.length - ext.length - 1)
42
+ if (chemin.endsWith('/index'))
43
+ chemin = chemin.substring(0, chemin.length - 6);
44
+
45
+ func( file_relatif, ext, chemin, dir );
46
+
47
+ }
48
+
49
+ } else if (func_sinon)
50
+ func_sinon( file_relatif );
51
+ };
52
+ }