Passed
Push — trunk ( 271fd6...3b104d )
by Christian
14:47 queued 13s
created

generate.ts ➔ getComponentNameFromArgumentNumber   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
/**
2
 * @private
3
 * @package admin
4
 */
5
import { CallExpression, Project, SourceFile, ts } from "ts-morph";
6
import * as path from "path";
7
import * as fs from "fs";
8
9
const project = new Project({
10
  skipAddingFilesFromTsConfig: true,
11
});
12
13
// load all the source files from the "src" directory
14
project.addSourceFilesAtPaths([
15
  "src/**/*{.js,.ts}",
16
  "!src/**/*{.spec.js,.spec.vue3.js,.d.ts,.types.ts}",
17
  "!src/meta/**/*",
18
]);
19
20
type componentInfo = {
21
  p: string, // path to import
22
  r: boolean, // needs register
23
  en?: string, // extends component name
24
  e?: boolean, // needs extends
25
}
26
27
function isComponentCall(call: CallExpression<ts.CallExpression>, functionString: string): boolean {
28
    const expression = call.getExpression();
29
30
    if (expression === null) {
31
      return false;
32
    }
33
34
    return [
35
      `Shopware.Component.${functionString}`,
36
      `Component.${functionString}`
37
    ].includes(expression.getText());
38
}
39
40
function getComponentNameFromArgumentNumber(call: CallExpression<ts.CallExpression>, argumentNumber: number): string {
41
  const argument = call.getArguments()[argumentNumber - 1];
42
43
  if (argument === null) {
44
    throw new Error(`Argument ${argumentNumber} not found in call ${call.getText()}`);
45
  }
46
47
  return argument.getText().replace(/['"]/g, '');
48
}
49
50
function throwIfComponentIsAlreadyRegistered(componentName: string, sourceFile: SourceFile): void {
51
  if (componentImportMap.hasOwnProperty(componentName)) {
52
    throw new Error(`Component ${componentName} already exists. Found again in file ${sourceFile.getFilePath()}`);
53
  }
54
}
55
56
function procsessComponentRegisterCall(sourceFile: SourceFile, call: CallExpression<ts.CallExpression>): void {
57
    const componentName = getComponentNameFromArgumentNumber(call, 1);
58
    throwIfComponentIsAlreadyRegistered(componentName, sourceFile);
59
60
    const secondArgument = call.getArguments()[1];
61
62
    // If the secondArgument is a ArrowFunction
63
    if (secondArgument.getKind() === ts.SyntaxKind.ArrowFunction) {
64
      // Get the import path inside the ArrowFunction
65
      const importPath = secondArgument
66
        .getDescendantsOfKind(ts.SyntaxKind.StringLiteral)[0]
67
        .getText()
68
        // remove all single and double quotes
69
        .replace(/['"]/g, '');
70
71
      // Check if the import path is relative
72
      let aliasPath = '';
73
      if (importPath.includes('./')) {
74
        // Get the path of the parent directory of this file
75
        const parentDirectory = sourceFile.getDirectoryPath();
76
        // Remove everything before and including "/app/administration/" from the parent directory
77
        const relativePath = parentDirectory.replace(/.*\/app\/administration\//, '');
78
        // Combine the relative path with the import path
79
        aliasPath = path.join(relativePath, importPath);
80
      } else {
81
        aliasPath = importPath;
82
      }
83
84
      componentImportMap[componentName] = {
85
        p: aliasPath,
86
        r: true,
87
      };
88
89
      return;
90
    }
91
92
    // If the secondArgument is a ObjectLiteralExpression
93
    if (secondArgument.getKind() === ts.SyntaxKind.ObjectLiteralExpression) {
94
      // Get the path of the parent directory of this file
95
      const path = sourceFile.getDirectoryPath().replace(/.*\/app\/administration\//, '');
96
97
      componentImportMap[componentName] = {
98
        p: path,
99
        r: false,
100
      };
101
    }
102
}
103
104
function procsessComponentExtendCall(sourceFile: SourceFile, call: CallExpression<ts.CallExpression>): void {
105
  const componentName = getComponentNameFromArgumentNumber(call, 1);
106
  const extendedComponentName = getComponentNameFromArgumentNumber(call, 2);
107
108
  throwIfComponentIsAlreadyRegistered(componentName, sourceFile);
109
110
  const thirdArgument = call.getArguments()[2];
111
112
  // If the thirdArgument is a ArrowFunction
113
  if (thirdArgument.getKind() === ts.SyntaxKind.ArrowFunction) {
114
    // Get the import path inside the ArrowFunction
115
    const importPath = thirdArgument
116
      .getDescendantsOfKind(ts.SyntaxKind.StringLiteral)[0]
117
      .getText()
118
      .replace(/['"]/g, '');
119
120
    // Check if the import path is relative
121
    let aliasPath = '';
122
    if (importPath.includes('./')) {
123
      // Get the path of the parent directory of this file
124
      const parentDirectory = sourceFile.getDirectoryPath();
125
      // Remove everything before and including "/app/administration/" from the parent directory
126
      const relativePath = parentDirectory.replace(/.*\/app\/administration\//, '');
127
      // Combine the relative path with the import path
128
      aliasPath = path.join(relativePath, importPath);
129
    } else {
130
      aliasPath = importPath;
131
    }
132
133
    componentImportMap[componentName] = {
134
      p: aliasPath,
135
      r: false,
136
      en: extendedComponentName,
137
      e: true,
138
    };
139
140
    return;
141
  }
142
143
  // If the thirdArgument is a ObjectLiteralExpression
144
  if (thirdArgument.getKind() === ts.SyntaxKind.ObjectLiteralExpression) {
145
    // Get the path of the parent directory of this file
146
    const path = sourceFile.getDirectoryPath().replace(/.*\/app\/administration\//, '');
147
148
    componentImportMap[componentName] = {
149
      p: path,
150
      r: false,
151
      en: extendedComponentName,
152
      e: false,
153
    };
154
  }
155
}
156
157
const componentImportMap: {[key: string]: componentInfo} = {};
158
159
for (const sourceFile of project.getSourceFiles()) {
160
  // print current file to console for progress tracking
161
  console.log(sourceFile.getFilePath());
162
163
  // collect all "Shopware.Component.register" or "Component.register" calls inside the file
164
  sourceFile.getDescendantsOfKind(
165
    ts.SyntaxKind.CallExpression,
166
  ).forEach(call => {
167
      if (isComponentCall(call, 'register')) {
168
        procsessComponentRegisterCall(sourceFile, call);
169
      }
170
171
      if (isComponentCall(call, 'extend')) {
172
        procsessComponentExtendCall(sourceFile, call);
173
      }
174
    }
175
  );
176
}
177
178
// Write output to file
179
const filestring = `/* eslint-disable */\n\nexport default ${JSON.stringify(componentImportMap)};`
180
fs.writeFileSync(path.join(__dirname, '/../../test/_helper_/componentWrapper/component-imports.js'), filestring);