@nasl/cli 0.1.19 → 0.2.0

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/dist/index.mjs CHANGED
@@ -121,9 +121,11 @@ function composeToString(files) {
121
121
  // 判断是否是特殊文件类型(variables 或 extensions)
122
122
  const isVariablesFile = nameFromPath === 'variables';
123
123
  const isExtensionsFile = arr[0] === 'extensions';
124
- const isSpecialFile = isVariablesFile || isExtensionsFile;
124
+ const isThemeCss = ext === 'css' && nameFromPath === 'theme';
125
+ const isSpecialFile = isVariablesFile || isExtensionsFile || isThemeCss;
125
126
  // 特殊文件的 namespace 包含文件名,普通文件不包含
126
127
  const namespace = isSpecialFile ? [...arr, nameFromPath].join('.') : arr.join('.');
128
+ let content = file.content;
127
129
  if (['ts', 'tsx'].includes(ext)) {
128
130
  if (isVariablesFile) {
129
131
  validateVariablesFile(file, errors);
@@ -135,7 +137,10 @@ function composeToString(files) {
135
137
  validateNormalFile(file, nameFromPath, namespace, errors);
136
138
  }
137
139
  }
138
- return `namespace ${namespace} {\n${file.content}\n}\n`;
140
+ else if (isThemeCss) {
141
+ content = ` $theme\`${content}\`;`;
142
+ }
143
+ return `namespace ${namespace} {\n${content}\n}\n`;
139
144
  })
140
145
  .join('\n');
141
146
  if (errors.length > 0) {
@@ -13711,22 +13716,108 @@ function writeFileWithLog(filePath, content, logger) {
13711
13716
  throw error;
13712
13717
  }
13713
13718
  }
13719
+
13720
+ /**
13721
+ * NASL 支持的所有文件类型配置
13722
+ */
13723
+ const NASL_FILE_TYPES = [
13724
+ {
13725
+ name: 'theme-css',
13726
+ description: '主题样式',
13727
+ fileNamePattern: 'app\\.frontendTypes\\.pc\\.frontends\\.pc\\.theme\\.css',
13728
+ codeRefPattern: 'app\\.frontendTypes\\.pc\\.frontends\\.pc\\.theme',
13729
+ extension: 'css',
13730
+ },
13731
+ {
13732
+ name: 'structures',
13733
+ description: '数据结构',
13734
+ fileNamePattern: 'app\\.structures\\.\\w+\\.ts',
13735
+ codeRefPattern: 'app\\.structures\\.\\w+(?:\\.\\w+)*',
13736
+ extension: 'ts',
13737
+ },
13738
+ {
13739
+ name: 'entities',
13740
+ description: '实体',
13741
+ fileNamePattern: 'app\\.dataSources\\.\\w+\\.entities\\.\\w+\\.ts',
13742
+ codeRefPattern: 'app\\.dataSources\\.\\w+\\.entities\\.\\w+(?:Entity)?(?:\\.\\w+)*',
13743
+ extension: 'ts',
13744
+ },
13745
+ {
13746
+ name: 'logics',
13747
+ description: '逻辑',
13748
+ fileNamePattern: 'app\\.logics\\.\\w+\\.ts',
13749
+ codeRefPattern: 'app\\.logics\\.\\w+(?:\\.\\w+)*',
13750
+ extension: 'ts',
13751
+ },
13752
+ {
13753
+ name: 'views',
13754
+ description: '视图',
13755
+ fileNamePattern: 'app\\.frontendTypes\\.\\w+\\.frontends\\.\\w+(?:\\.views\\.\\w+)+\\.tsx',
13756
+ codeRefPattern: 'app\\.frontendTypes\\.\\w+\\.frontends\\.\\w+(?:\\.views\\.\\w+)+(?:\\.\\w+)*',
13757
+ extension: 'tsx',
13758
+ },
13759
+ {
13760
+ name: 'backend-variables',
13761
+ description: '后端全局变量',
13762
+ fileNamePattern: 'app\\.backend\\.variables\\.ts',
13763
+ codeRefPattern: 'app\\.backend\\.variables(?:\\.\\w+)*',
13764
+ extension: 'ts',
13765
+ },
13766
+ {
13767
+ name: 'frontend-variables',
13768
+ description: '前端全局变量',
13769
+ fileNamePattern: 'app\\.frontendTypes\\.\\w+\\.frontends\\.\\w+\\.variables\\.ts',
13770
+ codeRefPattern: 'app\\.frontendTypes\\.\\w+\\.frontends\\.\\w+\\.variables(?:\\.\\w+)*',
13771
+ extension: 'ts',
13772
+ },
13773
+ {
13774
+ name: 'enums',
13775
+ description: '枚举',
13776
+ fileNamePattern: 'app\\.enums\\.\\w+\\.ts',
13777
+ codeRefPattern: 'app\\.enums\\.\\w+(?:\\.\\w+)*',
13778
+ extension: 'ts',
13779
+ },
13780
+ {
13781
+ name: 'extensions',
13782
+ description: '依赖库',
13783
+ fileNamePattern: 'extensions\\.\\w+\\.ts',
13784
+ codeRefPattern: 'extensions\\.\\w+(?:\\.\\w+)*',
13785
+ extension: 'ts',
13786
+ },
13787
+ ];
13788
+ /**
13789
+ * 获取用于验证文件名的正则表达式数组
13790
+ */
13791
+ function getFileNamePatterns() {
13792
+ return NASL_FILE_TYPES.map((type) => new RegExp(`^${type.fileNamePattern}$`));
13793
+ }
13794
+ const fileNamePatterns = getFileNamePatterns();
13795
+ /**
13796
+ * 获取用于提取代码引用的正则表达式数组
13797
+ */
13798
+ function getCodeRefPatterns() {
13799
+ return NASL_FILE_TYPES.map((type) => new RegExp(type.codeRefPattern, 'g'));
13800
+ }
13801
+ const codeRefPatterns = getCodeRefPatterns();
13714
13802
  /**
13715
13803
  * 判断文件路径是否为已知的 NASL 文件类型
13716
13804
  * 支持的类型:
13717
- * - 枚举 (enums)
13718
- * - 实体 (entities)
13719
- * - 数据结构 (structures)
13720
- * - 逻辑 (logics)
13721
- * - 页面 (views)
13722
- * - 前端/服务端全局变量 (variables)
13723
- * - 依赖库 (extensions)
13805
+ * - 数据结构 (structures): app.structures.{StructureName}.ts
13806
+ * - 实体 (entities): app.dataSources.{dsName}.entities.{EntityName}.ts
13807
+ * - 逻辑 (logics): app.logics.{logicName}.ts
13808
+ * - 视图 (views): app.frontendTypes.{type}.frontends.{name}.views.{viewName}.tsx
13809
+ * - 后端全局变量: app.backend.variables.ts
13810
+ * - 前端全局变量: app.frontendTypes.{type}.frontends.{name}.variables.ts
13811
+ * - 枚举 (enums): app.enums.{EnumName}.ts
13812
+ * - 依赖库 (extensions): extensions.{extensionName}.ts
13813
+ *
13814
+ * @param filePath 文件路径(绝对路径或相对路径)
13815
+ * @returns 是否为已知的 NASL 文件类型
13724
13816
  */
13725
13817
  function isKnownFileType(filePath) {
13726
- return (/\.(enums|entities|structures|logics|views)\.\w+\.(ts|tsx)$/.test(filePath) || // 枚举、实体、数据结构、逻辑、页面
13727
- /^app\..*\.variables\.ts$/.test(filePath) || // 前端/服务端全局变量 (以app开头,以variables.ts结尾)
13728
- /^extensions\.\w+\.(ts|tsx)$/.test(filePath) // 依赖库
13729
- );
13818
+ // 提取文件名
13819
+ const fileName = sysPath.basename(filePath);
13820
+ return fileNamePatterns.some((pattern) => pattern.test(fileName));
13730
13821
  }
13731
13822
 
13732
13823
  /**
@@ -13735,7 +13826,7 @@ function isKnownFileType(filePath) {
13735
13826
  async function scanNASLFiles(srcDir, representation, logger) {
13736
13827
  try {
13737
13828
  const pattern = representation === 'NaturalTS' ? '**/*.{ts,tsx}' : '**/*.nasl';
13738
- const files = await globby([pattern, '!**/*.css'], {
13829
+ const files = await globby([pattern, '**/app.frontendTypes.pc.frontends.pc.theme.css'], {
13739
13830
  cwd: srcDir,
13740
13831
  onlyFiles: true,
13741
13832
  absolute: false,
@@ -13749,7 +13840,6 @@ async function scanNASLFiles(srcDir, representation, logger) {
13749
13840
  }
13750
13841
  async function scanEntryFiles(projectRoot, patterns, logger) {
13751
13842
  try {
13752
- patterns.push('!**/*.css');
13753
13843
  const files = await globby(patterns, {
13754
13844
  cwd: projectRoot,
13755
13845
  onlyFiles: true,
@@ -13763,9 +13853,9 @@ async function scanEntryFiles(projectRoot, patterns, logger) {
13763
13853
  }
13764
13854
  }
13765
13855
  /**
13766
- * 从文件内容中提取 app.* 格式的依赖引用
13856
+ * 从文件内容中提取 指定 格式的依赖引用
13767
13857
  * @param content 文件内容
13768
- * @returns 依赖的 app.* 路径列表
13858
+ * @returns 依赖的 指定 路径列表
13769
13859
  */
13770
13860
  function extractDeps(content) {
13771
13861
  const deps = new Set();
@@ -13775,28 +13865,34 @@ function extractDeps(content) {
13775
13865
  .replace(/\/\*[\s\S]*?\*\//g, '') // 移除多行注释 /* ... */
13776
13866
  .replace(/'(?:[^'\\]|\\.)*'/g, '') // 移除单引号字符串 'xxx'
13777
13867
  .replace(/"(?:[^"\\]|\\.)*"/g, ''); // 移除双引号字符串 "xxx"
13778
- const allMatches = processedContent.matchAll(/(app|extensions)\.\w+\.[\w.]+/g); // 起码要2个点,支持 app.* 和 extensions.*
13779
- for (const match of allMatches) {
13780
- let dep = match[0];
13781
- if (/Entity$|Entity\./.test(dep)) {
13782
- dep = dep.replace(/Entity(\..*)?$/, '');
13783
- }
13784
- else if (/\.enums\.(\w+)\.(\w+)/.test(dep)) {
13785
- dep = dep.replace(/\.enums\.(\w+).+$/, '.enums.$1');
13786
- }
13787
- else if (/\.variables\.(\w+)/.test(dep)) {
13788
- // 处理 variables 依赖:app.backend.variables.xxx -> app.backend.variables
13789
- dep = dep.replace(/\.variables\..+$/, '.variables');
13790
- }
13791
- else if (/^extensions\.\w+\.\w+/.test(dep)) {
13792
- // 处理 extensions 依赖:extensions.lcap_auth.xxx -> extensions.lcap_auth
13793
- dep = dep.replace(/^(extensions\.\w+)\..+$/, '$1');
13794
- }
13795
- else if (/app\.dataSources\.\w+\.entities\.\w+\.\w+$/.test(dep)) {
13796
- continue; // 应该是写法有问题,跳过让后面的 checker 做检查
13868
+ for (const pattern of codeRefPatterns) {
13869
+ const matches = processedContent.matchAll(pattern);
13870
+ for (const match of matches) {
13871
+ let dep = match[0];
13872
+ // 处理 Entity 后缀:app.dataSources.ds.entities.EntityNameEntity -> app.dataSources.ds.entities.EntityName
13873
+ if (/Entity$|Entity\./.test(dep)) {
13874
+ dep = dep.replace(/Entity(\..*)?$/, '');
13875
+ }
13876
+ // 处理枚举:app.enums.EnumName.field -> app.enums.EnumName
13877
+ if (/^app\.enums\.\w+\./.test(dep)) {
13878
+ dep = dep.replace(/^(app\.enums\.\w+).+$/, '$1');
13879
+ }
13880
+ // 处理 variables:app.backend.variables.varName -> app.backend.variables
13881
+ if (/\.variables\.\w+/.test(dep)) {
13882
+ dep = dep.replace(/\.variables\..+$/, '.variables');
13883
+ }
13884
+ // 处理 extensions:extensions.lcap_auth.logics.getUser -> extensions.lcap_auth
13885
+ if (/^extensions\.\w+\./.test(dep)) {
13886
+ dep = dep.replace(/^(extensions\.\w+)\..+$/, '$1');
13887
+ }
13888
+ // 跳过不合法的实体引用(实体后还有字段的情况)
13889
+ if (/app\.dataSources\.\w+\.entities\.\w+\.\w+$/.test(dep)) {
13890
+ continue;
13891
+ }
13892
+ // 添加文件扩展名
13893
+ dep = `${dep}.${dep.includes('.views.') ? 'tsx' : 'ts'}`;
13894
+ deps.add(dep);
13797
13895
  }
13798
- dep = `${dep}.${dep.includes('.views.') ? 'tsx' : 'ts'}`;
13799
- deps.add(dep);
13800
13896
  }
13801
13897
  return Array.from(deps);
13802
13898
  }