如何使用 Node js 从 Angular 组件生成动态元数据?

问题描述 投票:0回答:1

我想创建一个库,其中包含由节点js代码自动生成的组件示例页面。 使用 Copilot 的帮助,我得到了这个函数来读取组件的元数据,但它返回的是空的。我对node的了解还不是很发达,我想了解这个过程,而不是仅仅复制AI。 这是带有接口的函数 - 代码位于节点的打字稿中。 该函数接收角度分量文件路径作为参数

interface InputMetadata {
  name: string;
  type: string | null;
  defaultValue: string | null;
}

interface ComponentMetadata {
  selector: string;
  standalone: boolean;
  inputs: InputMetadata[];
}

// Function to read component metadata
function readComponentMetadata(componentPath: string): ComponentMetadata {
  const componentFile = fs.readFileSync(componentPath, 'utf-8');
  const sourceFile = ts.createSourceFile(componentPath, componentFile, ts.ScriptTarget.Latest, true);
  const inputs: InputMetadata[] = [];
  let selector: string = '';
  let standalone: boolean = false;

  function visit(node: ts.Node) {
    if (ts.isClassDeclaration(node) && node.decorators) {
      node.decorators.forEach(decorator => {
        if (ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === 'Component') {
          const args = decorator.expression.arguments;
          if (args.length) {
            const componentMetadata = args[0] as ts.ObjectLiteralExpression;
            componentMetadata.properties.forEach(property => {
              if (ts.isPropertyAssignment(property)) {
                if (property.name.getText() === 'selector') {
                  selector = (property.initializer as ts.StringLiteral).text;
                } else if (property.name.getText() === 'standalone') {
                  standalone = (property.initializer.kind === ts.SyntaxKind.TrueKeyword);
                }
              }
            });
          }
        }
      });
    }
    if (ts.isPropertyDeclaration(node) && node.decorators) {
      node.decorators.forEach(decorator => {
        if (ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === 'Input') {
          const name = node.name.getText();
          const type = node.type ? node.type.getText() : null;
          const initializer = node.initializer ? node.initializer.getText() : null;
          inputs.push({name, type, defaultValue: initializer});
        }
      });
    }
    ts.forEachChild(node, visit);
  }

  visit(sourceFile);
  return {selector, standalone, inputs};
}

文件必须使用

npx tsc
“编译”,然后才能调用js文件。

我使用的节点和打字稿是:

"devDependencies": {
  "@types/node": "^22.10.1",
  "typescript": "^5.7.2"
}

这是 tsconfig.json 文件:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}
javascript node.js angular typescript
1个回答
0
投票

对我来说,代码抛出类型错误,就像评论中提到的那样。似乎

ClassDeclaration
没有
decorators
属性。要获取装饰器,您需要调用
ts.getDecorators(node)
。更新代码:

function readComponentMetadata(componentPath: string): ComponentMetadata {
  const componentFile = fs.readFileSync(componentPath, 'utf-8');
  const sourceFile = ts.createSourceFile(componentPath, componentFile, ts.ScriptTarget.Latest, true);
  const inputs: InputMetadata[] = [];
  let selector: string = '';
  let standalone: boolean = false;

  function visit(node: ts.Node) {
    if (ts.isClassDeclaration(node)) {
      const decorators = ts.getDecorators(node);
      decorators?.forEach(decorator => {
        if (ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === 'Component') {
          const args = decorator.expression.arguments;
          if (args.length) {
            const componentMetadata = args[0] as ts.ObjectLiteralExpression;
            componentMetadata.properties.forEach(property => {
              if (ts.isPropertyAssignment(property)) {
                if (property.name.getText() === 'selector') {
                  selector = (property.initializer as ts.StringLiteral).text;
                } else if (property.name.getText() === 'standalone') {
                  standalone = (property.initializer.kind === ts.SyntaxKind.TrueKeyword);
                }
              }
            });
          }
        }
      });
    }
    if (ts.isPropertyDeclaration(node)) {
      const decorators = ts.getDecorators(node);
      decorators?.forEach(decorator => {
        if (ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === 'Input') {
          const name = node.name.getText();
          const type = node.type ? node.type.getText() : null;
          const initializer = node.initializer ? node.initializer.getText() : null;
          inputs.push({name, type, defaultValue: initializer});
        }
      });
    }
    ts.forEachChild(node, visit);
  }

  visit(sourceFile);
  return {selector, standalone, inputs};
}

我还在一个真正的 Angular 项目中测试了这段代码,似乎工作得很好。

© www.soinside.com 2019 - 2024. All rights reserved.