mirror of
https://gitee.com/xtoon/xtoon-cloud.git
synced 2025-12-30 02:52:28 +00:00
通用模块开发
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
# Compiled class file
|
||||
*.class
|
||||
target
|
||||
logs
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
218
db/nacos-mysql.sql
Normal file
218
db/nacos-mysql.sql
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = config_info */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(255) DEFAULT NULL,
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`app_name` varchar(128) DEFAULT NULL,
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
`c_desc` varchar(256) DEFAULT NULL,
|
||||
`c_use` varchar(64) DEFAULT NULL,
|
||||
`effect` varchar(64) DEFAULT NULL,
|
||||
`type` varchar(64) DEFAULT NULL,
|
||||
`c_schema` text,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = config_info_aggr */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info_aggr` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(255) NOT NULL COMMENT 'group_id',
|
||||
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
|
||||
`content` longtext NOT NULL COMMENT '内容',
|
||||
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
|
||||
`app_name` varchar(128) DEFAULT NULL,
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = config_info_beta */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info_beta` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = config_info_tag */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info_tag` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = config_tags_relation */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_tags_relation` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'id',
|
||||
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
|
||||
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`nid` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`nid`),
|
||||
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
|
||||
KEY `idx_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = group_capacity */
|
||||
/******************************************/
|
||||
CREATE TABLE `group_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
|
||||
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_group_id` (`group_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = his_config_info */
|
||||
/******************************************/
|
||||
CREATE TABLE `his_config_info` (
|
||||
`id` bigint(64) unsigned NOT NULL,
|
||||
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`data_id` varchar(255) NOT NULL,
|
||||
`group_id` varchar(128) NOT NULL,
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`content` longtext NOT NULL,
|
||||
`md5` varchar(32) DEFAULT NULL,
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`src_user` text,
|
||||
`src_ip` varchar(50) DEFAULT NULL,
|
||||
`op_type` char(10) DEFAULT NULL,
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
PRIMARY KEY (`nid`),
|
||||
KEY `idx_gmt_create` (`gmt_create`),
|
||||
KEY `idx_gmt_modified` (`gmt_modified`),
|
||||
KEY `idx_did` (`data_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* 数据库全名 = nacos_config */
|
||||
/* 表名称 = tenant_capacity */
|
||||
/******************************************/
|
||||
CREATE TABLE `tenant_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
|
||||
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
|
||||
|
||||
|
||||
CREATE TABLE `tenant_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`kp` varchar(128) NOT NULL COMMENT 'kp',
|
||||
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
|
||||
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
|
||||
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
|
||||
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
|
||||
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
|
||||
KEY `idx_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`username` varchar(50) NOT NULL PRIMARY KEY,
|
||||
`password` varchar(500) NOT NULL,
|
||||
`enabled` boolean NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE `roles` (
|
||||
`username` varchar(50) NOT NULL,
|
||||
`role` varchar(50) NOT NULL,
|
||||
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
|
||||
);
|
||||
|
||||
CREATE TABLE `permissions` (
|
||||
`role` varchar(50) NOT NULL,
|
||||
`resource` varchar(255) NOT NULL,
|
||||
`action` varchar(8) NOT NULL,
|
||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||
);
|
||||
|
||||
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
|
||||
|
||||
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
|
||||
5
pom.xml
5
pom.xml
@@ -44,6 +44,11 @@
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!--bootstrap 启动器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
@@ -10,6 +10,28 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>xtoon-ops</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>xtoon-monitor-server</module>
|
||||
<module>xtoon-register-server</module>
|
||||
<module>xtoon-sentinel-server</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--监控-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<!--监控客户端-->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
59
xtoon-ops/xtoon-monitor-server/pom.xml
Normal file
59
xtoon-ops/xtoon-monitor-server/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>xtoon-ops</artifactId>
|
||||
<groupId>com.xtoon.cloud</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>xtoon-monitor-server</artifactId>
|
||||
|
||||
<name>xtoon-monitor-server</name>
|
||||
<description>监控服务</description>
|
||||
|
||||
<properties>
|
||||
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--监控服务端-->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-server</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
<!--注册中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<!--配置中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<!--undertow容器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<!--web 模块-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!-- LB 扩展 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.xtoon.cloud.ops.monitor;
|
||||
|
||||
import de.codecentric.boot.admin.server.config.EnableAdminServer;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
/**
|
||||
* 监控服务
|
||||
*
|
||||
* @author haoxin
|
||||
* @date 2021-05-24
|
||||
**/
|
||||
@EnableAdminServer
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class XtoonCloudMonitorApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(XtoonCloudMonitorApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.xtoon.cloud.ops.monitor.config;
|
||||
|
||||
import de.codecentric.boot.admin.server.config.AdminServerProperties;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
|
||||
/**
|
||||
* WebSecurityConfigurer
|
||||
*
|
||||
* @author haoxin
|
||||
* @date 2021-05-24
|
||||
**/
|
||||
@Configuration
|
||||
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final String adminContextPath;
|
||||
|
||||
public WebSecurityConfigurer(AdminServerProperties adminServerProperties) {
|
||||
this.adminContextPath = adminServerProperties.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
protected void configure(HttpSecurity http) {
|
||||
// @formatter:off
|
||||
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
successHandler.setTargetUrlParameter("redirectTo");
|
||||
successHandler.setDefaultTargetUrl(adminContextPath + "/");
|
||||
|
||||
http
|
||||
.headers().frameOptions().disable()
|
||||
.and().authorizeRequests()
|
||||
.antMatchers(adminContextPath + "/assets/**"
|
||||
, adminContextPath + "/login"
|
||||
, adminContextPath + "/instances/**"
|
||||
, adminContextPath + "/actuator/**"
|
||||
).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin().loginPage(adminContextPath + "/login")
|
||||
.successHandler(successHandler).and()
|
||||
.logout().logoutUrl(adminContextPath + "/logout")
|
||||
.and()
|
||||
.httpBasic().and()
|
||||
.csrf()
|
||||
.disable();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
29
xtoon-ops/xtoon-monitor-server/src/main/resources/bootstrap.yml
Executable file
29
xtoon-ops/xtoon-monitor-server/src/main/resources/bootstrap.yml
Executable file
@@ -0,0 +1,29 @@
|
||||
server:
|
||||
port: 5001
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: xtoon-monitor-server
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: localhost:8848
|
||||
config:
|
||||
server-addr: localhost:8848
|
||||
file-extension: yaml
|
||||
security:
|
||||
user:
|
||||
name: "admin"
|
||||
password: "admin"
|
||||
|
||||
management:
|
||||
health:
|
||||
redis:
|
||||
enabled: false
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
53
xtoon-ops/xtoon-register-server/pom.xml
Normal file
53
xtoon-ops/xtoon-register-server/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>xtoon-ops</artifactId>
|
||||
<groupId>com.xtoon.cloud</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>xtoon-register-server</artifactId>
|
||||
<description>nacos 注册配置中心</description>
|
||||
|
||||
<properties>
|
||||
<nacos.version>2.0.1.RELEASE</nacos.version>
|
||||
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud.nacos</groupId>
|
||||
<artifactId>nacos-config</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud.nacos</groupId>
|
||||
<artifactId>nacos-naming</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud.nacos</groupId>
|
||||
<artifactId>nacos-istio</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-system</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos;
|
||||
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import com.alibaba.nacos.config.ConfigConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* @author nacos
|
||||
* <p>
|
||||
* nacos console 源码运行,方便开发 生产建议从官网下载最新版配置运行
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
public class XtoonCloudNacosApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (initEnv()) {
|
||||
SpringApplication.run(XtoonCloudNacosApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化运行环境
|
||||
*/
|
||||
private static boolean initEnv() {
|
||||
// 特殊处理 window 且用户名包含中文的用户,避免RocksDB 初始化失败
|
||||
// System.setProperty(SystemUtil.USER_HOME, "/nacos-path/");
|
||||
if (SystemUtil.getOsInfo().isWindows() && Validator.hasChinese(SystemUtil.getUserInfo().getHomeDir())) {
|
||||
log.error("路径包含中文,需要打开以上注释配置指定不包含中文目录");
|
||||
return false;
|
||||
}
|
||||
|
||||
System.setProperty(ConfigConstants.STANDALONE_MODE, "true");
|
||||
System.setProperty(ConfigConstants.AUTH_ENABLED, "false");
|
||||
System.setProperty(ConfigConstants.LOG_BASEDIR, "logs");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2025, lengleng All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* Author: lengleng (wangiegie@gmail.com)
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.config;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-10-31
|
||||
* <p>
|
||||
* 覆盖nacos 默认配置
|
||||
*/
|
||||
public interface ConfigConstants {
|
||||
|
||||
/**
|
||||
* The System property name of Standalone mode
|
||||
*/
|
||||
String STANDALONE_MODE = "nacos.standalone";
|
||||
|
||||
/**
|
||||
* 是否开启认证
|
||||
*/
|
||||
String AUTH_ENABLED = "nacos.core.auth.enabled";
|
||||
|
||||
/**
|
||||
* 日志目录
|
||||
*/
|
||||
String LOG_BASEDIR = "server.tomcat.basedir";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.config;
|
||||
|
||||
import java.time.ZoneId;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import com.alibaba.nacos.core.code.ControllerMethodsCache;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Console config.
|
||||
*
|
||||
* @author yshen
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Component
|
||||
@EnableScheduling
|
||||
@PropertySource("/application.properties")
|
||||
public class ConsoleConfig {
|
||||
|
||||
@Autowired
|
||||
private ControllerMethodsCache methodsCache;
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.core.controller");
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.naming.controllers");
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.config.server.controller");
|
||||
methodsCache.initClassMethod("com.alibaba.nacos.controller");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.setMaxAge(18000L);
|
||||
config.addAllowedMethod("*");
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(ZoneId.systemDefault().toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.config.server.service.repository.PersistService;
|
||||
import com.alibaba.nacos.naming.controllers.OperatorController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Health Controller.
|
||||
*
|
||||
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
|
||||
*/
|
||||
@RestController("consoleHealth")
|
||||
@RequestMapping("/v1/console/health")
|
||||
public class HealthController {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HealthController.class);
|
||||
|
||||
private final PersistService persistService;
|
||||
|
||||
private final OperatorController apiCommands;
|
||||
|
||||
@Autowired
|
||||
public HealthController(PersistService persistService, OperatorController apiCommands) {
|
||||
this.persistService = persistService;
|
||||
this.apiCommands = apiCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the Nacos is in broken states or not, and cannot recover except by being
|
||||
* restarted.
|
||||
* @return HTTP code equal to 200 indicates that Nacos is in right states. HTTP code
|
||||
* equal to 500 indicates that Nacos is in broken states.
|
||||
*/
|
||||
@GetMapping("/liveness")
|
||||
public ResponseEntity liveness() {
|
||||
return ResponseEntity.ok().body("OK");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ready to receive the request or not.
|
||||
* @return HTTP code equal to 200 indicates that Nacos is ready. HTTP code equal to
|
||||
* 500 indicates that Nacos is not ready.
|
||||
*/
|
||||
@GetMapping("/readiness")
|
||||
public ResponseEntity readiness(HttpServletRequest request) {
|
||||
boolean isConfigReadiness = isConfigReadiness();
|
||||
boolean isNamingReadiness = isNamingReadiness(request);
|
||||
|
||||
if (isConfigReadiness && isNamingReadiness) {
|
||||
return ResponseEntity.ok().body("OK");
|
||||
}
|
||||
|
||||
if (!isConfigReadiness && !isNamingReadiness) {
|
||||
return ResponseEntity.status(500).body("Config and Naming are not in readiness");
|
||||
}
|
||||
|
||||
if (!isConfigReadiness) {
|
||||
return ResponseEntity.status(500).body("Config is not in readiness");
|
||||
}
|
||||
|
||||
return ResponseEntity.status(500).body("Naming is not in readiness");
|
||||
}
|
||||
|
||||
private boolean isConfigReadiness() {
|
||||
// check db
|
||||
try {
|
||||
persistService.configInfoCount("");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOGGER.error("Config health check fail.", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isNamingReadiness(HttpServletRequest request) {
|
||||
try {
|
||||
apiCommands.metrics(request);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOGGER.error("Naming health check fail.", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.config.server.model.TenantInfo;
|
||||
import com.alibaba.nacos.config.server.service.repository.PersistService;
|
||||
import com.alibaba.nacos.model.Namespace;
|
||||
import com.alibaba.nacos.model.NamespaceAllInfo;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* namespace service.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/v1/console/namespaces")
|
||||
public class NamespaceController {
|
||||
|
||||
@Autowired
|
||||
private PersistService persistService;
|
||||
|
||||
private final Pattern namespaceIdCheckPattern = Pattern.compile("^[\\w-]+");
|
||||
|
||||
private static final int NAMESPACE_ID_MAX_LENGTH = 128;
|
||||
|
||||
/**
|
||||
* Get namespace list.
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @return namespace list
|
||||
*/
|
||||
@GetMapping
|
||||
public RestResult<List<Namespace>> getNamespaces(HttpServletRequest request, HttpServletResponse response) {
|
||||
RestResult<List<Namespace>> rr = new RestResult<List<Namespace>>();
|
||||
rr.setCode(200);
|
||||
// TODO 获取用kp
|
||||
List<TenantInfo> tenantInfos = persistService.findTenantByKp("1");
|
||||
Namespace namespace0 = new Namespace("", "public", 200, persistService.configInfoCount(""), 0);
|
||||
List<Namespace> namespaces = new ArrayList<Namespace>();
|
||||
namespaces.add(namespace0);
|
||||
for (TenantInfo tenantInfo : tenantInfos) {
|
||||
int configCount = persistService.configInfoCount(tenantInfo.getTenantId());
|
||||
Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(), 200,
|
||||
configCount, 2);
|
||||
namespaces.add(namespaceTmp);
|
||||
}
|
||||
rr.setData(namespaces);
|
||||
return rr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get namespace all info by namespace id.
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @param namespaceId namespaceId
|
||||
* @return namespace all info
|
||||
*/
|
||||
@GetMapping(params = "show=all")
|
||||
public NamespaceAllInfo getNamespace(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam("namespaceId") String namespaceId) {
|
||||
// TODO 获取用kp
|
||||
if (StringUtils.isBlank(namespaceId)) {
|
||||
return new NamespaceAllInfo(namespaceId, "Public", 200, persistService.configInfoCount(""), 0,
|
||||
"Public Namespace");
|
||||
}
|
||||
else {
|
||||
TenantInfo tenantInfo = persistService.findTenantByKp("1", namespaceId);
|
||||
int configCount = persistService.configInfoCount(namespaceId);
|
||||
return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), 200, configCount, 2,
|
||||
tenantInfo.getTenantDesc());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create namespace.
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @param namespaceName namespace Name
|
||||
* @param namespaceDesc namespace Desc
|
||||
* @return whether create ok
|
||||
*/
|
||||
@PostMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
|
||||
public Boolean createNamespace(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam("customNamespaceId") String namespaceId, @RequestParam("namespaceName") String namespaceName,
|
||||
@RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
|
||||
// TODO 获取用kp
|
||||
if (StringUtils.isBlank(namespaceId)) {
|
||||
namespaceId = UUID.randomUUID().toString();
|
||||
}
|
||||
else {
|
||||
namespaceId = namespaceId.trim();
|
||||
if (!namespaceIdCheckPattern.matcher(namespaceId).matches()) {
|
||||
return false;
|
||||
}
|
||||
if (namespaceId.length() > NAMESPACE_ID_MAX_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
if (persistService.tenantInfoCountByTenantId(namespaceId) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
persistService.insertTenantInfoAtomic("1", namespaceId, namespaceName, namespaceDesc, "nacos",
|
||||
System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check namespaceId exist.
|
||||
* @param namespaceId namespace id
|
||||
* @return true if exist, otherwise false
|
||||
*/
|
||||
@GetMapping(params = "checkNamespaceIdExist=true")
|
||||
public Boolean checkNamespaceIdExist(@RequestParam("customNamespaceId") String namespaceId) {
|
||||
if (StringUtils.isBlank(namespaceId)) {
|
||||
return false;
|
||||
}
|
||||
return (persistService.tenantInfoCountByTenantId(namespaceId) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* edit namespace.
|
||||
* @param namespace namespace
|
||||
* @param namespaceShowName namespace ShowName
|
||||
* @param namespaceDesc namespace Desc
|
||||
* @return whether edit ok
|
||||
*/
|
||||
@PutMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
|
||||
public Boolean editNamespace(@RequestParam("namespace") String namespace,
|
||||
@RequestParam("namespaceShowName") String namespaceShowName,
|
||||
@RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
|
||||
// TODO 获取用kp
|
||||
persistService.updateTenantNameAtomic("1", namespace, namespaceShowName, namespaceDesc);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* del namespace by id.
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @param namespaceId namespace Id
|
||||
* @return whether del ok
|
||||
*/
|
||||
@DeleteMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
|
||||
public Boolean deleteConfig(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam("namespaceId") String namespaceId) {
|
||||
persistService.removeTenantInfoAtomic("1", namespaceId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Permission operation controller.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/v1/auth/permissions")
|
||||
public class PermissionController {
|
||||
|
||||
@Autowired
|
||||
private NacosRoleServiceImpl nacosRoleService;
|
||||
|
||||
/**
|
||||
* Query permissions of a role.
|
||||
* @param role the role
|
||||
* @param pageNo page index
|
||||
* @param pageSize page size
|
||||
* @return permission of a role
|
||||
*/
|
||||
@GetMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.READ)
|
||||
public Object getPermissions(@RequestParam int pageNo, @RequestParam int pageSize,
|
||||
@RequestParam(name = "role", defaultValue = StringUtils.EMPTY) String role) {
|
||||
return nacosRoleService.getPermissionsFromDatabase(role, pageNo, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a permission to a role.
|
||||
* @param role the role
|
||||
* @param resource the related resource
|
||||
* @param action the related action
|
||||
* @return ok if succeed
|
||||
*/
|
||||
@PostMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.WRITE)
|
||||
public Object addPermission(@RequestParam String role, @RequestParam String resource, @RequestParam String action) {
|
||||
nacosRoleService.addPermission(role, resource, action);
|
||||
return new RestResult<>(200, "add permission ok!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a permission from a role.
|
||||
* @param role the role
|
||||
* @param resource the related resource
|
||||
* @param action the related action
|
||||
* @return ok if succeed
|
||||
*/
|
||||
@DeleteMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "permissions", action = ActionTypes.WRITE)
|
||||
public Object deletePermission(@RequestParam String role, @RequestParam String resource,
|
||||
@RequestParam String action) {
|
||||
nacosRoleService.deletePermission(role, resource, action);
|
||||
return new RestResult<>(200, "delete permission ok!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Role operation controller.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/v1/auth/roles")
|
||||
public class RoleController {
|
||||
|
||||
@Autowired
|
||||
private NacosRoleServiceImpl roleService;
|
||||
|
||||
/**
|
||||
* Get roles list.
|
||||
* @param pageNo number index of page
|
||||
* @param pageSize page size
|
||||
* @param username optional, username of user
|
||||
* @return role list
|
||||
*/
|
||||
@GetMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
|
||||
public Object getRoles(@RequestParam int pageNo, @RequestParam int pageSize,
|
||||
@RequestParam(name = "username", defaultValue = "") String username) {
|
||||
return roleService.getRolesFromDatabase(username, pageNo, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuzzy matching role name .
|
||||
* @param role role id
|
||||
* @return role list
|
||||
*/
|
||||
@GetMapping("/search")
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
|
||||
public List<String> searchRoles(@RequestParam String role) {
|
||||
return roleService.findRolesLikeRoleName(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a role to a user
|
||||
*
|
||||
* <p>
|
||||
* This method is used for 2 functions: 1. create a role and bind it to GLOBAL_ADMIN.
|
||||
* 2. bind a role to an user.
|
||||
* @param role role name
|
||||
* @param username username
|
||||
* @return Code 200 and message 'add role ok!'
|
||||
*/
|
||||
@PostMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.WRITE)
|
||||
public Object addRole(@RequestParam String role, @RequestParam String username) {
|
||||
roleService.addRole(role, username);
|
||||
return new RestResult<>(200, "add role ok!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a role. If no username is specified, all users under this role are deleted.
|
||||
* @param role role
|
||||
* @param username username
|
||||
* @return ok if succeed
|
||||
*/
|
||||
@DeleteMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.WRITE)
|
||||
public Object deleteRole(@RequestParam String role,
|
||||
@RequestParam(name = "username", defaultValue = StringUtils.EMPTY) String username) {
|
||||
if (StringUtils.isBlank(username)) {
|
||||
roleService.deleteRole(role);
|
||||
}
|
||||
else {
|
||||
roleService.deleteRole(role, username);
|
||||
}
|
||||
return new RestResult<>(200, "delete role of user " + username + " ok!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.common.utils.VersionUtils;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Server state controller.
|
||||
*
|
||||
* @author xingxuechao on:2019/2/27 11:17 AM
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/v1/console/server")
|
||||
public class ServerStateController {
|
||||
|
||||
/**
|
||||
* Get server state of current server.
|
||||
* @return state json.
|
||||
*/
|
||||
@GetMapping("/state")
|
||||
public ResponseEntity serverState() {
|
||||
Map<String, String> serverState = new HashMap<>(3);
|
||||
serverState.put("standalone_mode",
|
||||
EnvUtil.getStandaloneMode() ? EnvUtil.STANDALONE_MODE_ALONE : EnvUtil.STANDALONE_MODE_CLUSTER);
|
||||
|
||||
serverState.put("function_mode", EnvUtil.getFunctionMode());
|
||||
serverState.put("version", VersionUtils.version);
|
||||
|
||||
return ResponseEntity.ok().body(serverState);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.controller;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.auth.annotation.Secured;
|
||||
import com.alibaba.nacos.auth.common.ActionTypes;
|
||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
||||
import com.alibaba.nacos.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.alibaba.nacos.common.utils.Objects;
|
||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||
import com.alibaba.nacos.config.server.model.User;
|
||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||
import com.alibaba.nacos.security.nacos.JwtTokenManager;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthManager;
|
||||
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUser;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||
import com.alibaba.nacos.utils.PasswordEncoderUtil;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User related methods entry.
|
||||
*
|
||||
* @author wfnuser
|
||||
* @author nkorange
|
||||
*/
|
||||
@RestController("user")
|
||||
@RequestMapping({ "/v1/auth", "/v1/auth/users" })
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private JwtTokenManager jwtTokenManager;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private NacosUserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private NacosRoleServiceImpl roleService;
|
||||
|
||||
@Autowired
|
||||
private AuthConfigs authConfigs;
|
||||
|
||||
@Autowired
|
||||
private NacosAuthManager authManager;
|
||||
|
||||
/**
|
||||
* Create a new user.
|
||||
* @param username username
|
||||
* @param password password
|
||||
* @return ok if create succeed
|
||||
* @throws IllegalArgumentException if user already exist
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
|
||||
@PostMapping
|
||||
public Object createUser(@RequestParam String username, @RequestParam String password) {
|
||||
|
||||
User user = userDetailsService.getUserFromDatabase(username);
|
||||
if (user != null) {
|
||||
throw new IllegalArgumentException("user '" + username + "' already exist!");
|
||||
}
|
||||
userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
|
||||
return new RestResult<>(200, "create user ok!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existed user.
|
||||
* @param username username of user
|
||||
* @return ok if deleted succeed, keep silent if user not exist
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@DeleteMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
|
||||
public Object deleteUser(@RequestParam String username) {
|
||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
||||
if (roleInfoList != null) {
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
||||
throw new IllegalArgumentException("cannot delete admin: " + username);
|
||||
}
|
||||
}
|
||||
}
|
||||
userDetailsService.deleteUser(username);
|
||||
return new RestResult<>(200, "delete user ok!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an user.
|
||||
* @param username username of user
|
||||
* @param newPassword new password of user
|
||||
* @param response http response
|
||||
* @param request http request
|
||||
* @return ok if update succeed
|
||||
* @throws IllegalArgumentException if user not exist or oldPassword is incorrect
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@PutMapping
|
||||
@Secured(resource = NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT, action = ActionTypes.WRITE)
|
||||
public Object updateUser(@RequestParam String username, @RequestParam String newPassword,
|
||||
HttpServletResponse response, HttpServletRequest request) throws IOException {
|
||||
// admin or same user
|
||||
if (!hasPermission(username, request)) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "authorization failed!");
|
||||
}
|
||||
|
||||
User user = userDetailsService.getUserFromDatabase(username);
|
||||
if (user == null) {
|
||||
throw new IllegalArgumentException("user " + username + " not exist!");
|
||||
}
|
||||
|
||||
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
|
||||
|
||||
return new RestResult<>(200, "update user ok!");
|
||||
}
|
||||
|
||||
private boolean hasPermission(String username, HttpServletRequest request) {
|
||||
if (!authConfigs.isAuthEnabled()) {
|
||||
return true;
|
||||
}
|
||||
if (Objects.isNull(request.getAttribute(RequestUtil.NACOS_USER_KEY))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NacosUser user = (NacosUser) request.getAttribute(RequestUtil.NACOS_USER_KEY);
|
||||
// admin
|
||||
if (user.isGlobalAdmin()) {
|
||||
return true;
|
||||
}
|
||||
// same user
|
||||
return user.getUserName().equals(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paged users.
|
||||
* @param pageNo number index of page
|
||||
* @param pageSize size of page
|
||||
* @return A collection of users, empty set if no user is found
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@GetMapping
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.READ)
|
||||
public Object getUsers(@RequestParam int pageNo, @RequestParam int pageSize) {
|
||||
return userDetailsService.getUsersFromDatabase(pageNo, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to Nacos
|
||||
*
|
||||
* <p>
|
||||
* This methods uses username and password to require a new token.
|
||||
* @param username username of user
|
||||
* @param password password
|
||||
* @param response http response
|
||||
* @param request http request
|
||||
* @return new token of the user
|
||||
* @throws AccessException if user info is incorrect
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response,
|
||||
HttpServletRequest request) throws AccessException {
|
||||
|
||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())
|
||||
|| AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
NacosUser user = (NacosUser) authManager.login(request);
|
||||
|
||||
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, NacosAuthConfig.TOKEN_PREFIX + user.getToken());
|
||||
|
||||
ObjectNode result = JacksonUtils.createEmptyJsonNode();
|
||||
// JSONObject result = new JSONObject();
|
||||
result.put(Constants.ACCESS_TOKEN, user.getToken());
|
||||
result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds());
|
||||
result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin());
|
||||
return result;
|
||||
}
|
||||
|
||||
// 通过用户名和密码创建一个 Authentication 认证对象,实现类为 UsernamePasswordAuthenticationToken
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
|
||||
password);
|
||||
|
||||
RestResult<String> rr = new RestResult<String>();
|
||||
try {
|
||||
// 通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证
|
||||
// Authentication 对象
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
// 将 Authentication 绑定到 SecurityContext
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
// 生成Token
|
||||
String token = jwtTokenManager.createToken(authentication);
|
||||
// 将Token写入到Http头部
|
||||
response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, "Bearer " + token);
|
||||
rr.setCode(200);
|
||||
rr.setData("Bearer " + token);
|
||||
return rr;
|
||||
}
|
||||
catch (BadCredentialsException authentication) {
|
||||
rr.setCode(401);
|
||||
rr.setMessage("Login failed");
|
||||
return rr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update password.
|
||||
* @param oldPassword old password
|
||||
* @param newPassword new password
|
||||
* @return Code 200 if update successfully, Code 401 if old password invalid,
|
||||
* otherwise 500
|
||||
*/
|
||||
@PutMapping("/password")
|
||||
@Deprecated
|
||||
public RestResult<String> updatePassword(@RequestParam(value = "oldPassword") String oldPassword,
|
||||
@RequestParam(value = "newPassword") String newPassword) {
|
||||
|
||||
RestResult<String> rr = new RestResult<String>();
|
||||
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
String username = ((UserDetails) principal).getUsername();
|
||||
User user = userDetailsService.getUserFromDatabase(username);
|
||||
String password = user.getPassword();
|
||||
|
||||
// TODO: throw out more fine grained exceptions
|
||||
try {
|
||||
if (PasswordEncoderUtil.matches(oldPassword, password)) {
|
||||
userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
|
||||
rr.setCode(200);
|
||||
rr.setMessage("Update password success");
|
||||
}
|
||||
else {
|
||||
rr.setCode(401);
|
||||
rr.setMessage("Old password is invalid");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
rr.setCode(500);
|
||||
rr.setMessage("Update userpassword failed");
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuzzy matching username.
|
||||
* @param username username
|
||||
* @return Matched username
|
||||
*/
|
||||
@GetMapping("/search")
|
||||
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
|
||||
public List<String> searchUsersLikeUsername(@RequestParam String username) {
|
||||
return userDetailsService.findUserLikeUsername(username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.exception;
|
||||
|
||||
import com.alibaba.nacos.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
/**
|
||||
* Exception handler for console module.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class ConsoleExceptionHandler {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleExceptionHandler.class);
|
||||
|
||||
@ExceptionHandler(AccessException.class)
|
||||
private ResponseEntity<String> handleAccessException(AccessException e) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getErrMsg());
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
private ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ExceptionUtil.getAllExceptionMsg(e));
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
private ResponseEntity<String> handleException(Exception e) {
|
||||
LOGGER.error("CONSOLE", e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ExceptionUtil.getAllExceptionMsg(e));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.filter;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.security.nacos.JwtTokenManager;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* jwt auth token filter.
|
||||
*
|
||||
* @author wfnuser
|
||||
*/
|
||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
private final JwtTokenManager tokenManager;
|
||||
|
||||
public JwtAuthenticationTokenFilter(JwtTokenManager tokenManager) {
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
String jwt = resolveToken(request);
|
||||
|
||||
if (StringUtils.isNotBlank(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
this.tokenManager.validateToken(jwt);
|
||||
Authentication authentication = this.tokenManager.getAuthentication(jwt);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token from header.
|
||||
*/
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
String jwt = request.getParameter(Constants.ACCESS_TOKEN);
|
||||
if (StringUtils.isNotBlank(jwt)) {
|
||||
return jwt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.model;
|
||||
|
||||
/**
|
||||
* Namespace.
|
||||
*
|
||||
* @author diamond
|
||||
*/
|
||||
public class Namespace {
|
||||
|
||||
private String namespace;
|
||||
|
||||
private String namespaceShowName;
|
||||
|
||||
private int quota;
|
||||
|
||||
private int configCount;
|
||||
|
||||
/**
|
||||
* 0 : Global configuration, 1 : Default private namespace ,2 : Custom namespace.
|
||||
*/
|
||||
private int type;
|
||||
|
||||
public String getNamespaceShowName() {
|
||||
return namespaceShowName;
|
||||
}
|
||||
|
||||
public void setNamespaceShowName(String namespaceShowName) {
|
||||
this.namespaceShowName = namespaceShowName;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public Namespace() {
|
||||
}
|
||||
|
||||
public Namespace(String namespace, String namespaceShowName) {
|
||||
this.namespace = namespace;
|
||||
this.namespaceShowName = namespaceShowName;
|
||||
}
|
||||
|
||||
public Namespace(String namespace, String namespaceShowName, int quota, int configCount, int type) {
|
||||
this.namespace = namespace;
|
||||
this.namespaceShowName = namespaceShowName;
|
||||
this.quota = quota;
|
||||
this.configCount = configCount;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getQuota() {
|
||||
return quota;
|
||||
}
|
||||
|
||||
public void setQuota(int quota) {
|
||||
this.quota = quota;
|
||||
}
|
||||
|
||||
public int getConfigCount() {
|
||||
return configCount;
|
||||
}
|
||||
|
||||
public void setConfigCount(int configCount) {
|
||||
this.configCount = configCount;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.model;
|
||||
|
||||
/**
|
||||
* all namespace info.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class NamespaceAllInfo extends Namespace {
|
||||
|
||||
private String namespaceDesc;
|
||||
|
||||
public String getNamespaceDesc() {
|
||||
return namespaceDesc;
|
||||
}
|
||||
|
||||
public void setNamespaceDesc(String namespaceDesc) {
|
||||
this.namespaceDesc = namespaceDesc;
|
||||
}
|
||||
|
||||
public NamespaceAllInfo() {
|
||||
}
|
||||
|
||||
public NamespaceAllInfo(String namespace, String namespaceShowName, int quota, int configCount, int type,
|
||||
String namespaceDesc) {
|
||||
super(namespace, namespaceShowName, quota, configCount, type);
|
||||
this.namespaceDesc = namespaceDesc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* auth provider.
|
||||
*
|
||||
* @author wfnuser
|
||||
*/
|
||||
@Component
|
||||
public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
@Autowired
|
||||
private NacosUserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
|
||||
String username = (String) authentication.getPrincipal();
|
||||
String password = (String) authentication.getCredentials();
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
if (!password.equals(userDetails.getPassword())) {
|
||||
return new UsernamePasswordAuthenticationToken(username, null, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass) {
|
||||
return aClass.equals(UsernamePasswordAuthenticationToken.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* jwt auth fail point.
|
||||
*
|
||||
* @author wfnuser
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
|
||||
throws IOException, ServletException {
|
||||
LOGGER.error("Responding with unauthorized error. Message:{}, url:{}", e.getMessage(), request.getRequestURI());
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JWT token manager.
|
||||
*
|
||||
* @author wfnuser
|
||||
* @author nkorange
|
||||
*/
|
||||
@Component
|
||||
public class JwtTokenManager {
|
||||
|
||||
private static final String AUTHORITIES_KEY = "auth";
|
||||
|
||||
@Autowired
|
||||
private AuthConfigs authConfigs;
|
||||
|
||||
/**
|
||||
* Create token.
|
||||
* @param authentication auth info
|
||||
* @return token
|
||||
*/
|
||||
public String createToken(Authentication authentication) {
|
||||
return createToken(authentication.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create token.
|
||||
* @param userName auth info
|
||||
* @return token
|
||||
*/
|
||||
public String createToken(String userName) {
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
Date validity;
|
||||
validity = new Date(now + authConfigs.getTokenValidityInSeconds() * 1000L);
|
||||
|
||||
Claims claims = Jwts.claims().setSubject(userName);
|
||||
return Jwts.builder().setClaims(claims).setExpiration(validity)
|
||||
.signWith(Keys.hmacShaKeyFor(authConfigs.getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auth Info.
|
||||
* @param token token
|
||||
* @return auth info
|
||||
*/
|
||||
public Authentication getAuthentication(String token) {
|
||||
Claims claims = Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build()
|
||||
.parseClaimsJws(token).getBody();
|
||||
|
||||
List<GrantedAuthority> authorities = AuthorityUtils
|
||||
.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
|
||||
|
||||
User principal = new User(claims.getSubject(), "", authorities);
|
||||
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* validate token.
|
||||
* @param token token
|
||||
*/
|
||||
public void validateToken(String token) {
|
||||
Jwts.parserBuilder().setSigningKey(authConfigs.getSecretKeyBytes()).build().parseClaimsJws(token);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||
import com.alibaba.nacos.config.server.model.User;
|
||||
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetails;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||
import com.alibaba.nacos.utils.PasswordEncoderUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.InitialLdapContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import static com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE;
|
||||
|
||||
/**
|
||||
* LDAP auth provider.
|
||||
*
|
||||
* @author zjw
|
||||
*/
|
||||
@Component
|
||||
public class LdapAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LdapAuthenticationProvider.class);
|
||||
|
||||
private static final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
|
||||
|
||||
private static final String TIMEOUT = "com.sun.jndi.ldap.connect.timeout";
|
||||
|
||||
private static final String DEFAULT_PASSWORD = "nacos";
|
||||
|
||||
private static final String LDAP_PREFIX = "LDAP_";
|
||||
|
||||
@Autowired
|
||||
private NacosUserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private NacosRoleServiceImpl nacosRoleService;
|
||||
|
||||
@Value(("${nacos.core.auth.ldap.url:ldap://localhost:389}"))
|
||||
private String ldapUrl;
|
||||
|
||||
@Value(("${nacos.core.auth.ldap.timeout:3000}"))
|
||||
private String time;
|
||||
|
||||
@Value(("${nacos.core.auth.ldap.userdn:cn={0},ou=user,dc=company,dc=com}"))
|
||||
private String userNamePattern;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
String username = (String) authentication.getPrincipal();
|
||||
String password = (String) authentication.getCredentials();
|
||||
|
||||
if (isAdmin(username)) {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
if (PasswordEncoderUtil.matches(password, userDetails.getPassword())) {
|
||||
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ldapLogin(username, password)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UserDetails userDetails;
|
||||
try {
|
||||
userDetails = userDetailsService.loadUserByUsername(LDAP_PREFIX + username);
|
||||
}
|
||||
catch (UsernameNotFoundException exception) {
|
||||
String nacosPassword = PasswordEncoderUtil.encode(DEFAULT_PASSWORD);
|
||||
userDetailsService.createUser(LDAP_PREFIX + username, nacosPassword);
|
||||
User user = new User();
|
||||
user.setUsername(LDAP_PREFIX + username);
|
||||
user.setPassword(nacosPassword);
|
||||
userDetails = new NacosUserDetails(user);
|
||||
}
|
||||
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
|
||||
}
|
||||
|
||||
private boolean isAdmin(String username) {
|
||||
List<RoleInfo> roleInfos = nacosRoleService.getRoles(username);
|
||||
if (CollectionUtils.isNotEmpty(roleInfos)) {
|
||||
for (RoleInfo roleinfo : roleInfos) {
|
||||
if (GLOBAL_ADMIN_ROLE.equals(roleinfo.getRole())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean ldapLogin(String username, String password) throws AuthenticationException {
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
|
||||
env.put(Context.PROVIDER_URL, ldapUrl);
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
|
||||
env.put(Context.SECURITY_PRINCIPAL, userNamePattern.replace("{0}", username));
|
||||
env.put(Context.SECURITY_CREDENTIALS, password);
|
||||
env.put(TIMEOUT, time);
|
||||
LdapContext ctx = null;
|
||||
try {
|
||||
ctx = new InitialLdapContext(env, null);
|
||||
}
|
||||
catch (CommunicationException e) {
|
||||
throw new RuntimeException("LDAP Service connect timeout");
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Exception cause by:{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
closeContext(ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass) {
|
||||
return aClass.equals(UsernamePasswordAuthenticationToken.class);
|
||||
}
|
||||
|
||||
private void closeContext(DirContext ctx) {
|
||||
if (ctx != null) {
|
||||
try {
|
||||
ctx.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Exception closing context", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||
import com.alibaba.nacos.auth.common.AuthSystemTypes;
|
||||
import com.alibaba.nacos.filter.JwtAuthenticationTokenFilter;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
||||
/**
|
||||
* Spring security config.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class NacosAuthConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";
|
||||
|
||||
public static final String LOGIN_ENTRY_POINT = "/v1/auth/login";
|
||||
|
||||
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/v1/auth/**";
|
||||
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
public static final String CONSOLE_RESOURCE_NAME_PREFIX = "console/";
|
||||
|
||||
public static final String UPDATE_PASSWORD_ENTRY_POINT = CONSOLE_RESOURCE_NAME_PREFIX + "user/password";
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Autowired
|
||||
private JwtTokenManager tokenProvider;
|
||||
|
||||
@Autowired
|
||||
private AuthConfigs authConfigs;
|
||||
|
||||
@Autowired
|
||||
private NacosUserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private LdapAuthenticationProvider ldapAuthenticationProvider;
|
||||
|
||||
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
|
||||
String ignoreUrls = null;
|
||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
ignoreUrls = "/**";
|
||||
}
|
||||
else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
ignoreUrls = "/**";
|
||||
}
|
||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
||||
ignoreUrls = env.getProperty("nacos.security.ignore.urls", "/**");
|
||||
}
|
||||
if (StringUtils.isNotBlank(ignoreUrls)) {
|
||||
for (String each : ignoreUrls.trim().split(SECURITY_IGNORE_URLS_SPILT_CHAR)) {
|
||||
web.ignoring().antMatchers(each.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
||||
}
|
||||
else if (AuthSystemTypes.LDAP.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) {
|
||||
auth.authenticationProvider(ldapAuthenticationProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
if (StringUtils.isBlank(authConfigs.getNacosAuthSystemType())) {
|
||||
http
|
||||
|
||||
.csrf().disable().cors() // We don't need CSRF for JWT based
|
||||
// authentication
|
||||
|
||||
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
|
||||
.and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
|
||||
.antMatchers(LOGIN_ENTRY_POINT).permitAll()
|
||||
|
||||
.and().authorizeRequests().antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()
|
||||
|
||||
.and().exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint());
|
||||
|
||||
// disable cache
|
||||
http.headers().cacheControl();
|
||||
|
||||
http.addFilterBefore(new JwtAuthenticationTokenFilter(tokenProvider),
|
||||
UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.remote.request.Request;
|
||||
import com.alibaba.nacos.auth.AuthManager;
|
||||
import com.alibaba.nacos.auth.exception.AccessException;
|
||||
import com.alibaba.nacos.auth.model.Permission;
|
||||
import com.alibaba.nacos.auth.model.User;
|
||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||
import com.alibaba.nacos.config.server.utils.RequestUtil;
|
||||
import com.alibaba.nacos.security.nacos.roles.NacosRoleServiceImpl;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUser;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Builtin access control entry of Nacos.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Component
|
||||
public class NacosAuthManager implements AuthManager {
|
||||
|
||||
private static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
@Autowired
|
||||
private JwtTokenManager tokenManager;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private NacosRoleServiceImpl roleService;
|
||||
|
||||
@Override
|
||||
public User login(Object request) throws AccessException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
String token = resolveToken(req);
|
||||
if (StringUtils.isBlank(token)) {
|
||||
throw new AccessException("user not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
tokenManager.validateToken(token);
|
||||
}
|
||||
catch (ExpiredJwtException e) {
|
||||
throw new AccessException("token expired!");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AccessException("token invalid!");
|
||||
}
|
||||
|
||||
Authentication authentication = tokenManager.getAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
String username = authentication.getName();
|
||||
NacosUser user = new NacosUser();
|
||||
user.setUserName(username);
|
||||
user.setToken(token);
|
||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
||||
if (roleInfoList != null) {
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
||||
user.setGlobalAdmin(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
req.setAttribute(RequestUtil.NACOS_USER_KEY, user);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User loginRemote(Object request) throws AccessException {
|
||||
Request req = (Request) request;
|
||||
String token = resolveToken(req);
|
||||
if (StringUtils.isBlank(token)) {
|
||||
throw new AccessException("user not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
tokenManager.validateToken(token);
|
||||
}
|
||||
catch (ExpiredJwtException e) {
|
||||
throw new AccessException("token expired!");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AccessException("token invalid!");
|
||||
}
|
||||
|
||||
Authentication authentication = tokenManager.getAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
String username = authentication.getName();
|
||||
NacosUser user = new NacosUser();
|
||||
user.setUserName(username);
|
||||
user.setToken(token);
|
||||
List<RoleInfo> roleInfoList = roleService.getRoles(username);
|
||||
if (roleInfoList != null) {
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
|
||||
user.setGlobalAdmin(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void auth(Permission permission, User user) throws AccessException {
|
||||
if (Loggers.AUTH.isDebugEnabled()) {
|
||||
Loggers.AUTH.debug("auth permission: {}, user: {}", permission, user);
|
||||
}
|
||||
|
||||
if (!roleService.hasPermission(user.getUserName(), permission)) {
|
||||
throw new AccessException("authorization failed!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token from header.
|
||||
*/
|
||||
private String resolveToken(HttpServletRequest request) throws AccessException {
|
||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
bearerToken = request.getParameter(Constants.ACCESS_TOKEN);
|
||||
if (StringUtils.isBlank(bearerToken)) {
|
||||
String userName = request.getParameter("username");
|
||||
String password = request.getParameter("password");
|
||||
bearerToken = resolveTokenFromUser(userName, password);
|
||||
}
|
||||
|
||||
return bearerToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token from header.
|
||||
*/
|
||||
private String resolveToken(Request request) throws AccessException {
|
||||
String bearerToken = request.getHeader(NacosAuthConfig.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
bearerToken = request.getHeader(Constants.ACCESS_TOKEN);
|
||||
if (StringUtils.isBlank(bearerToken)) {
|
||||
String userName = request.getHeader("username");
|
||||
String password = request.getHeader("password");
|
||||
bearerToken = resolveTokenFromUser(userName, password);
|
||||
}
|
||||
|
||||
return bearerToken;
|
||||
}
|
||||
|
||||
private String resolveTokenFromUser(String userName, String rawPassword) throws AccessException {
|
||||
String finalName;
|
||||
Authentication authenticate;
|
||||
try {
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName,
|
||||
rawPassword);
|
||||
authenticate = authenticationManager.authenticate(authenticationToken);
|
||||
}
|
||||
catch (AuthenticationException e) {
|
||||
throw new AccessException("unknown user!");
|
||||
}
|
||||
|
||||
if (null == authenticate || StringUtils.isBlank(authenticate.getName())) {
|
||||
finalName = userName;
|
||||
}
|
||||
else {
|
||||
finalName = authenticate.getName();
|
||||
}
|
||||
|
||||
return tokenManager.createToken(finalName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos.roles;
|
||||
|
||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||
import com.alibaba.nacos.auth.model.Permission;
|
||||
import com.alibaba.nacos.config.server.auth.PermissionInfo;
|
||||
import com.alibaba.nacos.config.server.auth.PermissionPersistService;
|
||||
import com.alibaba.nacos.config.server.auth.RoleInfo;
|
||||
import com.alibaba.nacos.config.server.auth.RolePersistService;
|
||||
import com.alibaba.nacos.config.server.model.Page;
|
||||
import com.alibaba.nacos.security.nacos.NacosAuthConfig;
|
||||
import com.alibaba.nacos.security.nacos.users.NacosUserDetailsServiceImpl;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.mina.util.ConcurrentHashSet;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Nacos builtin role service.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Service
|
||||
public class NacosRoleServiceImpl {
|
||||
|
||||
public static final String GLOBAL_ADMIN_ROLE = "ROLE_ADMIN";
|
||||
|
||||
@Autowired
|
||||
private AuthConfigs authConfigs;
|
||||
|
||||
@Autowired
|
||||
private RolePersistService rolePersistService;
|
||||
|
||||
@Autowired
|
||||
private NacosUserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private PermissionPersistService permissionPersistService;
|
||||
|
||||
private volatile Set<String> roleSet = new ConcurrentHashSet<>();
|
||||
|
||||
private volatile Map<String, List<RoleInfo>> roleInfoMap = new ConcurrentHashMap<>();
|
||||
|
||||
private volatile Map<String, List<PermissionInfo>> permissionInfoMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
|
||||
private void reload() {
|
||||
try {
|
||||
Page<RoleInfo> roleInfoPage = rolePersistService.getRolesByUserName(StringUtils.EMPTY, 1,
|
||||
Integer.MAX_VALUE);
|
||||
if (roleInfoPage == null) {
|
||||
return;
|
||||
}
|
||||
Set<String> tmpRoleSet = new HashSet<>(16);
|
||||
Map<String, List<RoleInfo>> tmpRoleInfoMap = new ConcurrentHashMap<>(16);
|
||||
for (RoleInfo roleInfo : roleInfoPage.getPageItems()) {
|
||||
if (!tmpRoleInfoMap.containsKey(roleInfo.getUsername())) {
|
||||
tmpRoleInfoMap.put(roleInfo.getUsername(), new ArrayList<>());
|
||||
}
|
||||
tmpRoleInfoMap.get(roleInfo.getUsername()).add(roleInfo);
|
||||
tmpRoleSet.add(roleInfo.getRole());
|
||||
}
|
||||
|
||||
Map<String, List<PermissionInfo>> tmpPermissionInfoMap = new ConcurrentHashMap<>(16);
|
||||
for (String role : tmpRoleSet) {
|
||||
Page<PermissionInfo> permissionInfoPage = permissionPersistService.getPermissions(role, 1,
|
||||
Integer.MAX_VALUE);
|
||||
tmpPermissionInfoMap.put(role, permissionInfoPage.getPageItems());
|
||||
}
|
||||
|
||||
roleSet = tmpRoleSet;
|
||||
roleInfoMap = tmpRoleInfoMap;
|
||||
permissionInfoMap = tmpPermissionInfoMap;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Loggers.AUTH.warn("[LOAD-ROLES] load failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user has permission of the resource.
|
||||
*
|
||||
* <p>
|
||||
* Note if the user has many roles, this method returns true if any one role of the
|
||||
* user has the desired permission.
|
||||
* @param username user info
|
||||
* @param permission permission to auth
|
||||
* @return true if granted, false otherwise
|
||||
*/
|
||||
public boolean hasPermission(String username, Permission permission) {
|
||||
// update password
|
||||
if (NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT.equals(permission.getResource())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<RoleInfo> roleInfoList = getRoles(username);
|
||||
if (Collections.isEmpty(roleInfoList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Global admin pass:
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
if (GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Old global admin can pass resource 'console/':
|
||||
if (permission.getResource().startsWith(NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For other roles, use a pattern match to decide if pass or not.
|
||||
for (RoleInfo roleInfo : roleInfoList) {
|
||||
List<PermissionInfo> permissionInfoList = getPermissions(roleInfo.getRole());
|
||||
if (Collections.isEmpty(permissionInfoList)) {
|
||||
continue;
|
||||
}
|
||||
for (PermissionInfo permissionInfo : permissionInfoList) {
|
||||
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
|
||||
String permissionAction = permissionInfo.getAction();
|
||||
if (permissionAction.contains(permission.getAction())
|
||||
&& Pattern.matches(permissionResource, permission.getResource())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<RoleInfo> getRoles(String username) {
|
||||
List<RoleInfo> roleInfoList = roleInfoMap.get(username);
|
||||
if (!authConfigs.isCachingEnabled()) {
|
||||
Page<RoleInfo> roleInfoPage = getRolesFromDatabase(username, 1, Integer.MAX_VALUE);
|
||||
if (roleInfoPage != null) {
|
||||
roleInfoList = roleInfoPage.getPageItems();
|
||||
}
|
||||
}
|
||||
return roleInfoList;
|
||||
}
|
||||
|
||||
public Page<RoleInfo> getRolesFromDatabase(String userName, int pageNo, int pageSize) {
|
||||
Page<RoleInfo> roles = rolePersistService.getRolesByUserName(userName, pageNo, pageSize);
|
||||
if (roles == null) {
|
||||
return new Page<>();
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
public List<PermissionInfo> getPermissions(String role) {
|
||||
List<PermissionInfo> permissionInfoList = permissionInfoMap.get(role);
|
||||
if (!authConfigs.isCachingEnabled()) {
|
||||
Page<PermissionInfo> permissionInfoPage = getPermissionsFromDatabase(role, 1, Integer.MAX_VALUE);
|
||||
if (permissionInfoPage != null) {
|
||||
permissionInfoList = permissionInfoPage.getPageItems();
|
||||
}
|
||||
}
|
||||
return permissionInfoList;
|
||||
}
|
||||
|
||||
public Page<PermissionInfo> getPermissionsByRoleFromDatabase(String role, int pageNo, int pageSize) {
|
||||
return permissionPersistService.getPermissions(role, pageNo, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add role.
|
||||
* @param role role name
|
||||
* @param username user name
|
||||
*/
|
||||
public void addRole(String role, String username) {
|
||||
if (userDetailsService.getUserFromDatabase(username) == null) {
|
||||
throw new IllegalArgumentException("user '" + username + "' not found!");
|
||||
}
|
||||
if (GLOBAL_ADMIN_ROLE.equals(role)) {
|
||||
throw new IllegalArgumentException("role '" + GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
|
||||
}
|
||||
rolePersistService.addRole(role, username);
|
||||
roleSet.add(role);
|
||||
}
|
||||
|
||||
public void deleteRole(String role, String userName) {
|
||||
rolePersistService.deleteRole(role, userName);
|
||||
}
|
||||
|
||||
public void deleteRole(String role) {
|
||||
rolePersistService.deleteRole(role);
|
||||
roleSet.remove(role);
|
||||
}
|
||||
|
||||
public Page<PermissionInfo> getPermissionsFromDatabase(String role, int pageNo, int pageSize) {
|
||||
Page<PermissionInfo> pageInfo = permissionPersistService.getPermissions(role, pageNo, pageSize);
|
||||
if (pageInfo == null) {
|
||||
return new Page<>();
|
||||
}
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add permission.
|
||||
* @param role role name
|
||||
* @param resource resource
|
||||
* @param action action
|
||||
*/
|
||||
public void addPermission(String role, String resource, String action) {
|
||||
if (!roleSet.contains(role)) {
|
||||
throw new IllegalArgumentException("role " + role + " not found!");
|
||||
}
|
||||
permissionPersistService.addPermission(role, resource, action);
|
||||
}
|
||||
|
||||
public void deletePermission(String role, String resource, String action) {
|
||||
permissionPersistService.deletePermission(role, resource, action);
|
||||
}
|
||||
|
||||
public List<String> findRolesLikeRoleName(String role) {
|
||||
return rolePersistService.findRolesLikeRoleName(role);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos.users;
|
||||
|
||||
import com.alibaba.nacos.auth.model.User;
|
||||
|
||||
/**
|
||||
* Nacos User.
|
||||
*
|
||||
* @author nkorange
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class NacosUser extends User {
|
||||
|
||||
private String token;
|
||||
|
||||
private boolean globalAdmin = false;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public boolean isGlobalAdmin() {
|
||||
return globalAdmin;
|
||||
}
|
||||
|
||||
public void setGlobalAdmin(boolean globalAdmin) {
|
||||
this.globalAdmin = globalAdmin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NacosUser{" + "token='" + token + '\'' + ", globalAdmin=" + globalAdmin + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos.users;
|
||||
|
||||
import com.alibaba.nacos.config.server.model.User;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* custom user.
|
||||
*
|
||||
* @author wfnuser
|
||||
*/
|
||||
public class NacosUserDetails implements UserDetails {
|
||||
|
||||
private final User user;
|
||||
|
||||
public NacosUserDetails(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
// TODO: get authorities
|
||||
return AuthorityUtils.commaSeparatedStringToAuthorityList("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.security.nacos.users;
|
||||
|
||||
import com.alibaba.nacos.auth.common.AuthConfigs;
|
||||
import com.alibaba.nacos.config.server.auth.UserPersistService;
|
||||
import com.alibaba.nacos.config.server.model.Page;
|
||||
import com.alibaba.nacos.config.server.model.User;
|
||||
import com.alibaba.nacos.core.utils.Loggers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Custem user service.
|
||||
*
|
||||
* @author wfnuser
|
||||
* @author nkorange
|
||||
*/
|
||||
@Service
|
||||
public class NacosUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
private Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private UserPersistService userPersistService;
|
||||
|
||||
@Autowired
|
||||
private AuthConfigs authConfigs;
|
||||
|
||||
@Scheduled(initialDelay = 5000, fixedDelay = 15000)
|
||||
private void reload() {
|
||||
try {
|
||||
Page<User> users = getUsersFromDatabase(1, Integer.MAX_VALUE);
|
||||
if (users == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, User> map = new ConcurrentHashMap<>(16);
|
||||
for (User user : users.getPageItems()) {
|
||||
map.put(user.getUsername(), user);
|
||||
}
|
||||
userMap = map;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Loggers.AUTH.warn("[LOAD-USERS] load failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
|
||||
User user = userMap.get(username);
|
||||
if (!authConfigs.isCachingEnabled()) {
|
||||
user = userPersistService.findUserByUsername(username);
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException(username);
|
||||
}
|
||||
return new NacosUserDetails(user);
|
||||
}
|
||||
|
||||
public void updateUserPassword(String username, String password) {
|
||||
userPersistService.updateUserPassword(username, password);
|
||||
}
|
||||
|
||||
public Page<User> getUsersFromDatabase(int pageNo, int pageSize) {
|
||||
return userPersistService.getUsers(pageNo, pageSize);
|
||||
}
|
||||
|
||||
public User getUser(String username) {
|
||||
User user = userMap.get(username);
|
||||
if (!authConfigs.isCachingEnabled()) {
|
||||
user = getUserFromDatabase(username);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public User getUserFromDatabase(String username) {
|
||||
return userPersistService.findUserByUsername(username);
|
||||
}
|
||||
|
||||
public List<String> findUserLikeUsername(String username) {
|
||||
return userPersistService.findUserLikeUsername(username);
|
||||
}
|
||||
|
||||
public void createUser(String username, String password) {
|
||||
userPersistService.createUser(username, password);
|
||||
}
|
||||
|
||||
public void deleteUser(String username) {
|
||||
userPersistService.deleteUser(username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.utils;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* Password encoder tool.
|
||||
*
|
||||
* @author nacos
|
||||
*/
|
||||
public class PasswordEncoderUtil {
|
||||
|
||||
public static Boolean matches(String raw, String encoded) {
|
||||
return new BCryptPasswordEncoder().matches(raw, encoded);
|
||||
}
|
||||
|
||||
public static String encode(String raw) {
|
||||
return new BCryptPasswordEncoder().encode(raw);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
server:
|
||||
port: 8848
|
||||
tomcat:
|
||||
basedir: logs
|
||||
|
||||
db:
|
||||
num: 1
|
||||
user: root
|
||||
password: haoxin963
|
||||
url:
|
||||
0: jdbc:mysql://localhost:3306/xtoon-cloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
|
||||
|
||||
|
||||
nacos:
|
||||
core:
|
||||
auth:
|
||||
system.type: nacos
|
||||
default.token.secret.key: SecretKey012345678901234567890123456789012345678901234567890123456789
|
||||
security:
|
||||
ignore:
|
||||
urls: /,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
platform: mysql
|
||||
security:
|
||||
enabled: false
|
||||
boot:
|
||||
admin:
|
||||
client:
|
||||
url: http://localhost:5001
|
||||
username: admin
|
||||
password: admin
|
||||
instance:
|
||||
prefer-ip: true
|
||||
|
||||
application:
|
||||
name: xtoon-register-server
|
||||
|
||||
useAddressServer: true
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: '*'
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
metrics:
|
||||
export:
|
||||
influx:
|
||||
enabled: false
|
||||
elastic:
|
||||
enabled: false
|
||||
1
xtoon-ops/xtoon-register-server/src/main/resources/nacos-version.txt
Executable file
1
xtoon-ops/xtoon-register-server/src/main/resources/nacos-version.txt
Executable file
@@ -0,0 +1 @@
|
||||
version=${project.version}
|
||||
7127
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/css/bootstrap.css
vendored
Normal file
7127
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0 !important;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cm-animate-fat-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
background-color: #7e7;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-rulers {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: -50px; bottom: -20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
top: 0; bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
min-height: 100%;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -30px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
|
||||
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-font-variant-ligatures: contextual;
|
||||
font-variant-ligatures: contextual;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-rtl pre { direction: rtl; }
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
File diff suppressed because one or more lines are too long
2102
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/css/font-awesome.css
vendored
Normal file
2102
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/css/font-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
/*无边框*/
|
||||
font-family: "iconfont-1";
|
||||
src: url('icon1/iconfont.eot?t=1458627591'); /* IE9*/
|
||||
src: url('icon1/iconfont.eot?t=1458627591#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('icon1/iconfont.woff?t=1458627591') format('woff'), /* chrome, firefox */ url('icon1/iconfont.ttf?t=1458627591') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('icon1/iconfont.svg?t=1458627591#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
/*有边框*/
|
||||
font-family: "iconfont-2";
|
||||
src: url('icon/iconfont.eot'); /* IE9*/
|
||||
src: url('icon/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('icon/iconfont.woff') format('woff'), /* chrome, firefox */ url('icon/iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('icon/iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
/* 有边框 */
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-stroke-width: 0.2px;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconfont-1 {
|
||||
/*无边框*/
|
||||
|
||||
font-family: "iconfont-1" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-stroke-width: 0.2px;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconfont-2 {
|
||||
/*有边框*/
|
||||
font-family: "iconfont-2" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-stroke-width: 0.2px;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
||||
}
|
||||
|
||||
.panel-logo {
|
||||
padding-right: 2px;
|
||||
font-size: 18px;
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.icon-lg {
|
||||
font-size: 80px !important;
|
||||
}
|
||||
|
||||
.icon-size-md {
|
||||
font-size: 40px !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.icon-size-lg {
|
||||
font-size: 80px !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.icon-hsf:before {
|
||||
content: "\e62f" !important;
|
||||
}
|
||||
|
||||
.icon-rocketmq:before {
|
||||
content: "\e632" !important;
|
||||
}
|
||||
|
||||
.icon-notify:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-tddl:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-pandora:before {
|
||||
content: "\e622" !important;
|
||||
}
|
||||
|
||||
.icon-ailtomcat:before {
|
||||
content: "\e628" !important;
|
||||
}
|
||||
|
||||
.icon-configserver:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-diamondserver:before {
|
||||
content: "\e62a" !important;
|
||||
}
|
||||
|
||||
.icon-vipserver:before {
|
||||
content: "\e625" !important;
|
||||
}
|
||||
|
||||
.icon-eagleeye:before {
|
||||
content: "\e62c" !important;
|
||||
}
|
||||
|
||||
.icon-tengine:before {
|
||||
content: "\e635" !important;
|
||||
}
|
||||
|
||||
.icon-tair:before {
|
||||
content: "\e634" !important;
|
||||
}
|
||||
|
||||
.icon-hbase:before {
|
||||
content: "\e62d" !important;
|
||||
}
|
||||
|
||||
.icon-jstorm:before {
|
||||
content: "\e627" !important;
|
||||
}
|
||||
|
||||
.icon-histore:before {
|
||||
content: "\e62e" !important;
|
||||
}
|
||||
|
||||
.icon-jingwei:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-txc:before {
|
||||
content: "\e636" !important;
|
||||
}
|
||||
|
||||
.icon-edas:before {
|
||||
content: "\e620" !important;
|
||||
}
|
||||
|
||||
.icon-csb:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-ons:before {
|
||||
content: "\e630" !important;
|
||||
}
|
||||
|
||||
.icon-drds:before {
|
||||
content: "\e61f" !important;
|
||||
}
|
||||
|
||||
.icon-duct:before {
|
||||
content: "\e62b" !important;
|
||||
}
|
||||
|
||||
.icon-amazon:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-autoload:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-switch:before {
|
||||
content: "\e633" !important;
|
||||
}
|
||||
|
||||
.icon-sentinel:before {
|
||||
content: "\e623" !important;
|
||||
}
|
||||
|
||||
.icon-preplan:before {
|
||||
content: "\e631" !important;
|
||||
}
|
||||
|
||||
.icon-moses:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-zeus:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-athena:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-bcp:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-lark:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-nest:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-monkeyking:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-tab:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-oceanus:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-eos :before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-sonar:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-ai:before {
|
||||
content: "\e605" !important;
|
||||
}
|
||||
|
||||
.icon-hotcode:before {
|
||||
content: "\e621" !important;
|
||||
}
|
||||
|
||||
.icon-taokeeper:before {
|
||||
content: "\e624" !important;
|
||||
}
|
||||
|
||||
.icon-mdl:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-mw:before {
|
||||
content: "\e61e" !important;
|
||||
}
|
||||
|
||||
.icon-default:before {
|
||||
content: "\e607" !important;
|
||||
}
|
||||
|
||||
.icon-alitomcat:before {
|
||||
content: "\e607" !important;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.CodeMirror-merge {
|
||||
position: relative;
|
||||
border: 1px solid #ddd;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }
|
||||
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }
|
||||
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
|
||||
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
|
||||
|
||||
.CodeMirror-merge-pane {
|
||||
display: inline-block;
|
||||
white-space: normal;
|
||||
vertical-align: top;
|
||||
}
|
||||
.CodeMirror-merge-pane-rightmost {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-gap {
|
||||
z-index: 2;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
position: relative;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-scrolllock-wrap {
|
||||
position: absolute;
|
||||
bottom: 0; left: 50%;
|
||||
}
|
||||
.CodeMirror-merge-scrolllock {
|
||||
position: relative;
|
||||
left: -50%;
|
||||
cursor: pointer;
|
||||
color: #555;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
right: 0; bottom: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copy {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #44c;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copy-reverse {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #44c;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
|
||||
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
|
||||
|
||||
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-r-chunk { background: #ffffe0; }
|
||||
.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }
|
||||
.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }
|
||||
.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }
|
||||
|
||||
.CodeMirror-merge-l-chunk { background: #eef; }
|
||||
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
|
||||
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
|
||||
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
|
||||
|
||||
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
|
||||
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
|
||||
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
|
||||
|
||||
.CodeMirror-merge-collapsed-widget:before {
|
||||
content: "(...)";
|
||||
}
|
||||
.CodeMirror-merge-collapsed-widget {
|
||||
cursor: pointer;
|
||||
color: #88b;
|
||||
background: #eef;
|
||||
border: 1px solid #ddf;
|
||||
font-size: 90%;
|
||||
padding: 0 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 114 B |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 390.21"><defs><style>.cls-1{fill:#fff}.cls-2{fill:url(#未命名的渐变_7)}</style><linearGradient id="未命名的渐变_7" x1="816.73" y1="195.1" x2="1492.16" y2="195.1" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4190ff"/><stop offset="1" stop-color="#1be1f6"/></linearGradient></defs><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M1788 389.24h-175.45v-77.1H1788c7.13 0 17.72-1.53 26.06-5.83 8.08-4.17 16.35-10.47 16.35-32.72 0-21.89-8.25-28-16.31-32-7.22-3.59-17.1-5.59-27.1-5.59h-69.4c-5.4 0-33.74-.78-61.47-16.17-36.18-20.08-56.13-55.13-56.13-100.46 0-45.17 19.81-80.33 55.78-100.75a133.14 133.14 0 0 1 61.8-16.83h161.92v77.1h-161.76c-.77 0-13.5.64-24.5 7.14-7.5 4.44-16.12 11.39-16.12 33.34s8.58 28.58 16.05 32.83c9.44 5.37 20.87 6.65 24.48 6.69H1787c22.16 0 43.38 4.73 61.37 13.67 38.12 18.94 59.11 54.2 59.11 101 0 46.59-20.64 81.92-58.11 101.25-24.31 12.56-48.91 14.43-61.37 14.43zm-1498.84-3.85c-11.54 0-23.71-3.26-31.17-12.66L72.29 146.09l1 241.22H1l-1-347C0 23.94 9.41 11.27 24.9 5.87s33.65-1.38 43.85 11.47l184.74 228.57V2h72.29l1 346.76c0 16.4-9.41 29.08-24.9 34.48a38.48 38.48 0 0 1-12.72 2.15z"/><path class="cls-2" d="M937.33 390.21c-107.58 0-195.1-87.52-195.1-195.1S829.75 0 937.33 0a193.92 193.92 0 0 1 137.17 56.36l.16.15 52.64 52.64-54.52 54.52-52.56-52.56a118 118 0 1 0 .56 167.43l53.91-53.91 54.52 54.52-53.91 53.91a193.83 193.83 0 0 1-137.97 57.15z"/><path class="cls-2" d="M1379.86 390.21a194 194 0 0 1-137-56.17l-.38-.38-137.2-139.15L1241.9 57.14A193.83 193.83 0 0 1 1379.86 0C1487.44 0 1575 87.52 1575 195.1s-87.56 195.11-195.14 195.11zm-82.66-110.9a118 118 0 1 0-.76-167.67l-82.64 83.1z"/><path class="cls-1" d="M442.45 386.35L552.52 98.73a84.56 84.56 0 0 1 5.35-10.8 79.54 79.54 0 0 1 4.62 9.35l111.4 289.07h82.88L634.2 68.95A164.41 164.41 0 0 0 619 40.2C597.63 8.45 573.9 1.79 557.75 1.79c-29.44 0-49.78 21.48-61.67 39.5a172.83 172.83 0 0 0-15.37 29.34L359.64 386.35z"/><circle cx="1966.27" cy="356.47" r="33.73" fill="#1be1f6"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
|
||||
if (old == CodeMirror.Init) old = false;
|
||||
if (!old == !val) return;
|
||||
if (val) setFullscreen(cm);
|
||||
else setNormal(cm);
|
||||
});
|
||||
|
||||
function setFullscreen(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = "";
|
||||
wrap.style.height = "auto";
|
||||
wrap.className += " CodeMirror-fullscreen";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
cm.refresh();
|
||||
}
|
||||
|
||||
function setNormal(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
|
||||
document.documentElement.style.overflow = "";
|
||||
var info = cm.state.fullScreenRestore;
|
||||
wrap.style.width = info.width; wrap.style.height = info.height;
|
||||
window.scrollTo(info.scrollLeft, info.scrollTop);
|
||||
cm.refresh();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Depends on jsonlint.js from https://github.com/zaach/jsonlint
|
||||
|
||||
// declare global: jsonlint
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("lint", "json", function(text) {
|
||||
var found = [];
|
||||
jsonlint.parseError = function(str, hash) {
|
||||
var loc = hash.loc;
|
||||
found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str});
|
||||
};
|
||||
try { jsonlint.parse(text); }
|
||||
catch(e) {}
|
||||
return found;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
|
||||
function showTooltip(e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip";
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
|
||||
tt.style.left = (e.clientX + 5) + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(e, content, node) {
|
||||
var tooltip = showTooltip(e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n && n.nodeType == 11) n = n.host;
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, options, hasGutter) {
|
||||
this.marked = [];
|
||||
this.options = options;
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
this.waitingFor = 0
|
||||
}
|
||||
|
||||
function parseOptions(_cm, options) {
|
||||
if (options instanceof Function) return {getAnnotations: options};
|
||||
if (!options || options === true) options = {};
|
||||
return options;
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function makeMarker(labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message-" + severity;
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
return tip;
|
||||
}
|
||||
|
||||
function lintAsync(cm, getAnnotations, passOptions) {
|
||||
var state = cm.state.lint
|
||||
var id = ++state.waitingFor
|
||||
function abort() {
|
||||
id = -1
|
||||
cm.off("change", abort)
|
||||
}
|
||||
cm.on("change", abort)
|
||||
getAnnotations(cm.getValue(), function(annotations, arg2) {
|
||||
cm.off("change", abort)
|
||||
if (state.waitingFor != id) return
|
||||
if (arg2 && annotations instanceof CodeMirror) annotations = arg2
|
||||
updateLinting(cm, annotations)
|
||||
}, passOptions, cm);
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint, options = state.options;
|
||||
var passOptions = options.options || options; // Support deprecated passing of `options` property in options
|
||||
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!getAnnotations) return;
|
||||
if (options.async || getAnnotations.async) {
|
||||
lintAsync(cm, getAnnotations, passOptions)
|
||||
} else {
|
||||
updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm));
|
||||
}
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
clearMarks(cm);
|
||||
var state = cm.state.lint, options = state.options;
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
|
||||
state.options.tooltips));
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
|
||||
}
|
||||
|
||||
function popupTooltips(annotations, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
var tooltip = document.createDocumentFragment();
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var ann = annotations[i];
|
||||
tooltip.appendChild(annotationTooltip(ann));
|
||||
}
|
||||
showTooltipFor(e, tooltip, target);
|
||||
}
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
|
||||
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
|
||||
|
||||
var annotations = [];
|
||||
for (var i = 0; i < spans.length; ++i) {
|
||||
annotations.push(spans[i].__annotation);
|
||||
}
|
||||
if (annotations.length) popupTooltips(annotations, e);
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lint", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
if (cm.state.lint.options.lintOnChange !== false)
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
clearTimeout(cm.state.lint.timeout);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
|
||||
if (state.options.lintOnChange !== false)
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false)
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("performLint", function() {
|
||||
if (this.state.lint) startLinting(this);
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function Context(indented, column, type, info, align, prev) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.info = info;
|
||||
this.align = align;
|
||||
this.prev = prev;
|
||||
}
|
||||
function pushContext(state, col, type, info) {
|
||||
var indent = state.indented;
|
||||
if (state.context && state.context.type == "statement" && type != "statement")
|
||||
indent = state.context.indented;
|
||||
return state.context = new Context(indent, col, type, info, null, state.context);
|
||||
}
|
||||
function popContext(state) {
|
||||
var t = state.context.type;
|
||||
if (t == ")" || t == "]" || t == "}")
|
||||
state.indented = state.context.indented;
|
||||
return state.context = state.context.prev;
|
||||
}
|
||||
|
||||
function typeBefore(stream, state, pos) {
|
||||
if (state.prevToken == "variable" || state.prevToken == "type") return true;
|
||||
if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
|
||||
if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
|
||||
}
|
||||
|
||||
function isTopScope(context) {
|
||||
for (;;) {
|
||||
if (!context || context.type == "top") return true;
|
||||
if (context.type == "}" && context.prev.info != "namespace") return false;
|
||||
context = context.prev;
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("clike", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit,
|
||||
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
|
||||
dontAlignCalls = parserConfig.dontAlignCalls,
|
||||
keywords = parserConfig.keywords || {},
|
||||
types = parserConfig.types || {},
|
||||
builtin = parserConfig.builtin || {},
|
||||
blockKeywords = parserConfig.blockKeywords || {},
|
||||
defKeywords = parserConfig.defKeywords || {},
|
||||
atoms = parserConfig.atoms || {},
|
||||
hooks = parserConfig.hooks || {},
|
||||
multiLineStrings = parserConfig.multiLineStrings,
|
||||
indentStatements = parserConfig.indentStatements !== false,
|
||||
indentSwitch = parserConfig.indentSwitch !== false,
|
||||
namespaceSeparator = parserConfig.namespaceSeparator,
|
||||
isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
|
||||
numberStart = parserConfig.numberStart || /[\d\.]/,
|
||||
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
|
||||
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
|
||||
isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/;
|
||||
|
||||
var curPunc, isDefKeyword;
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (hooks[ch]) {
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
if (isPunctuationChar.test(ch)) {
|
||||
curPunc = ch;
|
||||
return null;
|
||||
}
|
||||
if (numberStart.test(ch)) {
|
||||
stream.backUp(1)
|
||||
if (stream.match(number)) return "number"
|
||||
stream.next()
|
||||
}
|
||||
if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
}
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
if (isOperatorChar.test(ch)) {
|
||||
while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
|
||||
return "operator";
|
||||
}
|
||||
stream.eatWhile(isIdentifierChar);
|
||||
if (namespaceSeparator) while (stream.match(namespaceSeparator))
|
||||
stream.eatWhile(isIdentifierChar);
|
||||
|
||||
var cur = stream.current();
|
||||
if (contains(keywords, cur)) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
if (contains(defKeywords, cur)) isDefKeyword = true;
|
||||
return "keyword";
|
||||
}
|
||||
if (contains(types, cur)) return "type";
|
||||
if (contains(builtin, cur)) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
return "builtin";
|
||||
}
|
||||
if (contains(atoms, cur)) return "atom";
|
||||
return "variable";
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) {end = true; break;}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (end || !(escaped || multiLineStrings))
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
|
||||
function maybeEOL(stream, state) {
|
||||
if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
|
||||
state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: null,
|
||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
|
||||
indented: 0,
|
||||
startOfLine: true,
|
||||
prevToken: null
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var ctx = state.context;
|
||||
if (stream.sol()) {
|
||||
if (ctx.align == null) ctx.align = false;
|
||||
state.indented = stream.indentation();
|
||||
state.startOfLine = true;
|
||||
}
|
||||
if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
|
||||
curPunc = isDefKeyword = null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style == "comment" || style == "meta") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
|
||||
while (state.context.type == "statement") popContext(state);
|
||||
else if (curPunc == "{") pushContext(state, stream.column(), "}");
|
||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
||||
else if (curPunc == "}") {
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
if (ctx.type == "}") ctx = popContext(state);
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
}
|
||||
else if (curPunc == ctx.type) popContext(state);
|
||||
else if (indentStatements &&
|
||||
(((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
|
||||
(ctx.type == "statement" && curPunc == "newstatement"))) {
|
||||
pushContext(state, stream.column(), "statement", stream.current());
|
||||
}
|
||||
|
||||
if (style == "variable" &&
|
||||
((state.prevToken == "def" ||
|
||||
(parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
|
||||
isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
|
||||
style = "def";
|
||||
|
||||
if (hooks.token) {
|
||||
var result = hooks.token(stream, state, style);
|
||||
if (result !== undefined) style = result;
|
||||
}
|
||||
|
||||
if (style == "def" && parserConfig.styleDefs === false) style = "variable";
|
||||
|
||||
state.startOfLine = false;
|
||||
state.prevToken = isDefKeyword ? "def" : style || curPunc;
|
||||
maybeEOL(stream, state);
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;
|
||||
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
|
||||
if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
|
||||
if (parserConfig.dontIndentStatements)
|
||||
while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
|
||||
ctx = ctx.prev
|
||||
if (hooks.indent) {
|
||||
var hook = hooks.indent(state, ctx, textAfter);
|
||||
if (typeof hook == "number") return hook
|
||||
}
|
||||
var closing = firstChar == ctx.type;
|
||||
var switchBlock = ctx.prev && ctx.prev.info == "switch";
|
||||
if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
|
||||
while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
|
||||
return ctx.indented
|
||||
}
|
||||
if (ctx.type == "statement")
|
||||
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
|
||||
if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
|
||||
return ctx.column + (closing ? 0 : 1);
|
||||
if (ctx.type == ")" && !closing)
|
||||
return ctx.indented + statementIndentUnit;
|
||||
|
||||
return ctx.indented + (closing ? 0 : indentUnit) +
|
||||
(!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0);
|
||||
},
|
||||
|
||||
electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
lineComment: "//",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function words(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
function contains(words, word) {
|
||||
if (typeof words === "function") {
|
||||
return words(word);
|
||||
} else {
|
||||
return words.propertyIsEnumerable(word);
|
||||
}
|
||||
}
|
||||
var cKeywords = "auto if break case register continue return default do sizeof " +
|
||||
"static else struct switch extern typedef union for goto while enum const volatile";
|
||||
var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
|
||||
|
||||
function cppHook(stream, state) {
|
||||
if (!state.startOfLine) return false
|
||||
for (var ch, next = null; ch = stream.peek();) {
|
||||
if (ch == "\\" && stream.match(/^.$/)) {
|
||||
next = cppHook
|
||||
break
|
||||
} else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
|
||||
break
|
||||
}
|
||||
stream.next()
|
||||
}
|
||||
state.tokenize = next
|
||||
return "meta"
|
||||
}
|
||||
|
||||
function pointerHook(_stream, state) {
|
||||
if (state.prevToken == "type") return "type";
|
||||
return false;
|
||||
}
|
||||
|
||||
function cpp14Literal(stream) {
|
||||
stream.eatWhile(/[\w\.']/);
|
||||
return "number";
|
||||
}
|
||||
|
||||
function cpp11StringHook(stream, state) {
|
||||
stream.backUp(1);
|
||||
// Raw strings.
|
||||
if (stream.match(/(R|u8R|uR|UR|LR)/)) {
|
||||
var match = stream.match(/"([^\s\\()]{0,16})\(/);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
state.cpp11RawStringDelim = match[1];
|
||||
state.tokenize = tokenRawString;
|
||||
return tokenRawString(stream, state);
|
||||
}
|
||||
// Unicode strings/chars.
|
||||
if (stream.match(/(u8|u|U|L)/)) {
|
||||
if (stream.match(/["']/, /* eat */ false)) {
|
||||
return "string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Ignore this hook.
|
||||
stream.next();
|
||||
return false;
|
||||
}
|
||||
|
||||
function cppLooksLikeConstructor(word) {
|
||||
var lastTwo = /(\w+)::~?(\w+)$/.exec(word);
|
||||
return lastTwo && lastTwo[1] == lastTwo[2];
|
||||
}
|
||||
|
||||
// C#-style strings where "" escapes a quote.
|
||||
function tokenAtString(stream, state) {
|
||||
var next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == '"' && !stream.eat('"')) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
// C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
|
||||
// <delim> can be a string up to 16 characters long.
|
||||
function tokenRawString(stream, state) {
|
||||
// Escape characters that have special regex meanings.
|
||||
var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&');
|
||||
var match = stream.match(new RegExp(".*?\\)" + delim + '"'));
|
||||
if (match)
|
||||
state.tokenize = null;
|
||||
else
|
||||
stream.skipToEnd();
|
||||
return "string";
|
||||
}
|
||||
|
||||
function def(mimes, mode) {
|
||||
if (typeof mimes == "string") mimes = [mimes];
|
||||
var words = [];
|
||||
function add(obj) {
|
||||
if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
|
||||
words.push(prop);
|
||||
}
|
||||
add(mode.keywords);
|
||||
add(mode.types);
|
||||
add(mode.builtin);
|
||||
add(mode.atoms);
|
||||
if (words.length) {
|
||||
mode.helperType = mimes[0];
|
||||
CodeMirror.registerHelper("hintWords", mimes[0], words);
|
||||
}
|
||||
|
||||
for (var i = 0; i < mimes.length; ++i)
|
||||
CodeMirror.defineMIME(mimes[i], mode);
|
||||
}
|
||||
|
||||
def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords),
|
||||
types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " +
|
||||
"int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " +
|
||||
"uint32_t uint64_t"),
|
||||
blockKeywords: words("case do else for if switch while struct"),
|
||||
defKeywords: words("struct"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("null true false"),
|
||||
hooks: {"#": cppHook, "*": pointerHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def(["text/x-c++src", "text/x-c++hdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " +
|
||||
"static_cast typeid catch operator template typename class friend private " +
|
||||
"this using const_cast inline public throw virtual delete mutable protected " +
|
||||
"alignas alignof constexpr decltype nullptr noexcept thread_local final " +
|
||||
"static_assert override"),
|
||||
types: words(cTypes + " bool wchar_t"),
|
||||
blockKeywords: words("catch class do else finally for if struct switch try while"),
|
||||
defKeywords: words("class namespace struct enum union"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
dontIndentStatements: /^template$/,
|
||||
isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"*": pointerHook,
|
||||
"u": cpp11StringHook,
|
||||
"U": cpp11StringHook,
|
||||
"L": cpp11StringHook,
|
||||
"R": cpp11StringHook,
|
||||
"0": cpp14Literal,
|
||||
"1": cpp14Literal,
|
||||
"2": cpp14Literal,
|
||||
"3": cpp14Literal,
|
||||
"4": cpp14Literal,
|
||||
"5": cpp14Literal,
|
||||
"6": cpp14Literal,
|
||||
"7": cpp14Literal,
|
||||
"8": cpp14Literal,
|
||||
"9": cpp14Literal,
|
||||
token: function(stream, state, style) {
|
||||
if (style == "variable" && stream.peek() == "(" &&
|
||||
(state.prevToken == ";" || state.prevToken == null ||
|
||||
state.prevToken == "}") &&
|
||||
cppLooksLikeConstructor(stream.current()))
|
||||
return "def";
|
||||
}
|
||||
},
|
||||
namespaceSeparator: "::",
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-java", {
|
||||
name: "clike",
|
||||
keywords: words("abstract assert break case catch class const continue default " +
|
||||
"do else enum extends final finally float for goto if implements import " +
|
||||
"instanceof interface native new package private protected public " +
|
||||
"return static strictfp super switch synchronized this throw throws transient " +
|
||||
"try volatile while @interface"),
|
||||
types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
|
||||
"Integer Long Number Object Short String StringBuffer StringBuilder Void"),
|
||||
blockKeywords: words("catch class do else finally for if switch try while"),
|
||||
defKeywords: words("class interface package enum @interface"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
// Don't match the @interface keyword.
|
||||
if (stream.match('interface', false)) return false;
|
||||
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
},
|
||||
modeProps: {fold: ["brace", "import"]}
|
||||
});
|
||||
|
||||
def("text/x-csharp", {
|
||||
name: "clike",
|
||||
keywords: words("abstract as async await base break case catch checked class const continue" +
|
||||
" default delegate do else enum event explicit extern finally fixed for" +
|
||||
" foreach goto if implicit in interface internal is lock namespace new" +
|
||||
" operator out override params private protected public readonly ref return sealed" +
|
||||
" sizeof stackalloc static struct switch this throw try typeof unchecked" +
|
||||
" unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
|
||||
" global group into join let orderby partial remove select set value var yield"),
|
||||
types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" +
|
||||
" Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" +
|
||||
" UInt64 bool byte char decimal double short int long object" +
|
||||
" sbyte float string ushort uint ulong"),
|
||||
blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
|
||||
defKeywords: words("class interface namespace struct var"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"@": function(stream, state) {
|
||||
if (stream.eat('"')) {
|
||||
state.tokenize = tokenAtString;
|
||||
return tokenAtString(stream, state);
|
||||
}
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function tokenTripleString(stream, state) {
|
||||
var escaped = false;
|
||||
while (!stream.eol()) {
|
||||
if (!escaped && stream.match('"""')) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
escaped = stream.next() == "\\" && !escaped;
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
def("text/x-scala", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
|
||||
/* scala */
|
||||
"abstract case catch class def do else extends final finally for forSome if " +
|
||||
"implicit import lazy match new null object override package private protected return " +
|
||||
"sealed super this throw trait try type val var while with yield _ " +
|
||||
|
||||
/* package scala */
|
||||
"assert assume require print println printf readLine readBoolean readByte readShort " +
|
||||
"readChar readInt readLong readFloat readDouble"
|
||||
),
|
||||
types: words(
|
||||
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
|
||||
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
|
||||
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
|
||||
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
|
||||
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
|
||||
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
|
||||
),
|
||||
multiLineStrings: true,
|
||||
blockKeywords: words("catch class enum do else finally for forSome if match switch try while"),
|
||||
defKeywords: words("class enum def object package trait type val var"),
|
||||
atoms: words("true false null"),
|
||||
indentStatements: false,
|
||||
indentSwitch: false,
|
||||
isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
if (!stream.match('""')) return false;
|
||||
state.tokenize = tokenTripleString;
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"'": function(stream) {
|
||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
return "atom";
|
||||
},
|
||||
"=": function(stream, state) {
|
||||
var cx = state.context
|
||||
if (cx.type == "}" && cx.align && stream.eat(">")) {
|
||||
state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
|
||||
return "operator"
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
modeProps: {closeBrackets: {triples: '"'}}
|
||||
});
|
||||
|
||||
function tokenKotlinString(tripleString){
|
||||
return function (stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
|
||||
if (tripleString && stream.match('"""')) {end = true; break;}
|
||||
next = stream.next();
|
||||
if(!escaped && next == "$" && stream.match('{'))
|
||||
stream.skipTo("}");
|
||||
escaped = !escaped && next == "\\" && !tripleString;
|
||||
}
|
||||
if (end || !tripleString)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-kotlin", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
/*keywords*/
|
||||
"package as typealias class interface this super val " +
|
||||
"var fun for is in This throw return " +
|
||||
"break continue object if else while do try when !in !is as? " +
|
||||
|
||||
/*soft keywords*/
|
||||
"file import where by get set abstract enum open inner override private public internal " +
|
||||
"protected catch finally out final vararg reified dynamic companion constructor init " +
|
||||
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
|
||||
"external annotation crossinline const operator infix suspend"
|
||||
),
|
||||
types: words(
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
|
||||
),
|
||||
intendSwitch: false,
|
||||
indentStatements: false,
|
||||
multiLineStrings: true,
|
||||
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
|
||||
blockKeywords: words("catch class do else finally for if where try while enum"),
|
||||
defKeywords: words("class val var object package interface fun"),
|
||||
atoms: words("true false null this"),
|
||||
hooks: {
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenKotlinString(stream.match('""'));
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
},
|
||||
modeProps: {closeBrackets: {triples: '"'}}
|
||||
});
|
||||
|
||||
def(["x-shader/x-vertex", "x-shader/x-fragment"], {
|
||||
name: "clike",
|
||||
keywords: words("sampler1D sampler2D sampler3D samplerCube " +
|
||||
"sampler1DShadow sampler2DShadow " +
|
||||
"const attribute uniform varying " +
|
||||
"break continue discard return " +
|
||||
"for while do if else struct " +
|
||||
"in out inout"),
|
||||
types: words("float int bool void " +
|
||||
"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
|
||||
"mat2 mat3 mat4"),
|
||||
blockKeywords: words("for while do if else struct"),
|
||||
builtin: words("radians degrees sin cos tan asin acos atan " +
|
||||
"pow exp log exp2 sqrt inversesqrt " +
|
||||
"abs sign floor ceil fract mod min max clamp mix step smoothstep " +
|
||||
"length distance dot cross normalize ftransform faceforward " +
|
||||
"reflect refract matrixCompMult " +
|
||||
"lessThan lessThanEqual greaterThan greaterThanEqual " +
|
||||
"equal notEqual any all not " +
|
||||
"texture1D texture1DProj texture1DLod texture1DProjLod " +
|
||||
"texture2D texture2DProj texture2DLod texture2DProjLod " +
|
||||
"texture3D texture3DProj texture3DLod texture3DProjLod " +
|
||||
"textureCube textureCubeLod " +
|
||||
"shadow1D shadow2D shadow1DProj shadow2DProj " +
|
||||
"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
|
||||
"dFdx dFdy fwidth " +
|
||||
"noise1 noise2 noise3 noise4"),
|
||||
atoms: words("true false " +
|
||||
"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
|
||||
"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
|
||||
"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
|
||||
"gl_FogCoord gl_PointCoord " +
|
||||
"gl_Position gl_PointSize gl_ClipVertex " +
|
||||
"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
|
||||
"gl_TexCoord gl_FogFragCoord " +
|
||||
"gl_FragCoord gl_FrontFacing " +
|
||||
"gl_FragData gl_FragDepth " +
|
||||
"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
|
||||
"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
|
||||
"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
|
||||
"gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
|
||||
"gl_ProjectionMatrixInverseTranspose " +
|
||||
"gl_ModelViewProjectionMatrixInverseTranspose " +
|
||||
"gl_TextureMatrixInverseTranspose " +
|
||||
"gl_NormalScale gl_DepthRange gl_ClipPlane " +
|
||||
"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
|
||||
"gl_FrontLightModelProduct gl_BackLightModelProduct " +
|
||||
"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
|
||||
"gl_FogParameters " +
|
||||
"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
|
||||
"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
|
||||
"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
|
||||
"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
|
||||
"gl_MaxDrawBuffers"),
|
||||
indentSwitch: false,
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-nesc", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
|
||||
"implementation includes interface module new norace nx_struct nx_union post provides " +
|
||||
"signal task uses abstract extends"),
|
||||
types: words(cTypes),
|
||||
blockKeywords: words("case do else for if switch while struct"),
|
||||
atoms: words("null true false"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-objectivec", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " +
|
||||
"inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
|
||||
types: words(cTypes),
|
||||
atoms: words("YES NO NULL NILL ON OFF true false"),
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$]/);
|
||||
return "keyword";
|
||||
},
|
||||
"#": cppHook,
|
||||
indent: function(_state, ctx, textAfter) {
|
||||
if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
|
||||
}
|
||||
},
|
||||
modeProps: {fold: "brace"}
|
||||
});
|
||||
|
||||
def("text/x-squirrel", {
|
||||
name: "clike",
|
||||
keywords: words("base break clone continue const default delete enum extends function in class" +
|
||||
" foreach local resume return this throw typeof yield constructor instanceof static"),
|
||||
types: words(cTypes),
|
||||
blockKeywords: words("case catch class else for foreach if switch try while"),
|
||||
defKeywords: words("function local class"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
// Ceylon Strings need to deal with interpolation
|
||||
var stringTokenizer = null;
|
||||
function tokenCeylonString(type) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!escaped && stream.match('"') &&
|
||||
(type == "single" || stream.match('""'))) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
if (!escaped && stream.match('``')) {
|
||||
stringTokenizer = tokenCeylonString(type);
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
next = stream.next();
|
||||
escaped = type == "single" && !escaped && next == "\\";
|
||||
}
|
||||
if (end)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-ceylon", {
|
||||
name: "clike",
|
||||
keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
|
||||
" exists extends finally for function given if import in interface is let module new" +
|
||||
" nonempty object of out outer package return satisfies super switch then this throw" +
|
||||
" try value void while"),
|
||||
types: function(word) {
|
||||
// In Ceylon all identifiers that start with an uppercase are types
|
||||
var first = word.charAt(0);
|
||||
return (first === first.toUpperCase() && first !== first.toLowerCase());
|
||||
},
|
||||
blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
|
||||
defKeywords: words("class dynamic function interface module object package value"),
|
||||
builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
|
||||
" native optional sealed see serializable shared suppressWarnings tagged throws variable"),
|
||||
isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
|
||||
isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
|
||||
numberStart: /[\d#$]/,
|
||||
number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
|
||||
multiLineStrings: true,
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null larger smaller equal empty finished"),
|
||||
indentSwitch: false,
|
||||
styleDefs: false,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
'`': function(stream, state) {
|
||||
if (!stringTokenizer || !stream.match('`')) return false;
|
||||
state.tokenize = stringTokenizer;
|
||||
stringTokenizer = null;
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"'": function(stream) {
|
||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
return "atom";
|
||||
},
|
||||
token: function(_stream, state, style) {
|
||||
if ((style == "variable" || style == "type") &&
|
||||
state.prevToken == ".") {
|
||||
return "variable-2";
|
||||
}
|
||||
}
|
||||
},
|
||||
modeProps: {
|
||||
fold: ["brace", "import"],
|
||||
closeBrackets: {triples: '"'}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Jison generated parser */
|
||||
var jsonlint = (function(){
|
||||
var parser = {trace: function trace() { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
|
||||
productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
|
||||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: // replace escaped characters with actual character
|
||||
this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
.replace(/\\v/g,'\v')
|
||||
.replace(/\\f/g,'\f')
|
||||
.replace(/\\b/g,'\b');
|
||||
|
||||
break;
|
||||
case 2:this.$ = Number(yytext);
|
||||
break;
|
||||
case 3:this.$ = null;
|
||||
break;
|
||||
case 4:this.$ = true;
|
||||
break;
|
||||
case 5:this.$ = false;
|
||||
break;
|
||||
case 6:return this.$ = $$[$0-1];
|
||||
break;
|
||||
case 13:this.$ = {};
|
||||
break;
|
||||
case 14:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 15:this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 16:this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 17:this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 18:this.$ = [];
|
||||
break;
|
||||
case 19:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 20:this.$ = [$$[$0]];
|
||||
break;
|
||||
case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}],
|
||||
defaultActions: {16:[2,6]},
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this,
|
||||
stack = [0],
|
||||
vstack = [null], // semantic value stack
|
||||
lstack = [], // location stack
|
||||
table = this.table,
|
||||
yytext = '',
|
||||
yylineno = 0,
|
||||
yyleng = 0,
|
||||
recovering = 0,
|
||||
TERROR = 2,
|
||||
EOF = 1;
|
||||
|
||||
//this.reductionCount = this.shiftCount = 0;
|
||||
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
if (typeof this.lexer.yylloc == 'undefined')
|
||||
this.lexer.yylloc = {};
|
||||
var yyloc = this.lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
|
||||
if (typeof this.yy.parseError === 'function')
|
||||
this.parseError = this.yy.parseError;
|
||||
|
||||
function popStack (n) {
|
||||
stack.length = stack.length - 2*n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
|
||||
function lex() {
|
||||
var token;
|
||||
token = self.lexer.lex() || 1; // $end = 1
|
||||
// if token isn't its numeric value, convert
|
||||
if (typeof token !== 'number') {
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
||||
while (true) {
|
||||
// retreive state number from top of stack
|
||||
state = stack[stack.length-1];
|
||||
|
||||
// use default actions if available
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol == null)
|
||||
symbol = lex();
|
||||
// read action for current state and first input
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
|
||||
// handle parse error
|
||||
_handle_error:
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
var errStr = '';
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||||
} else {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||||
(symbol == 1 /*EOF*/ ? "end of input" :
|
||||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||||
}
|
||||
this.parseError(errStr,
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if ((TERROR.toString()) in table[state]) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
}
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||||
}
|
||||
|
||||
switch (action[0]) {
|
||||
|
||||
case 1: // shift
|
||||
//this.shiftCount++;
|
||||
|
||||
stack.push(symbol);
|
||||
vstack.push(this.lexer.yytext);
|
||||
lstack.push(this.lexer.yylloc);
|
||||
stack.push(action[1]); // push state
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) { // normal execution/no error
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
if (recovering > 0)
|
||||
recovering--;
|
||||
} else { // error just occurred, resume old lookahead f/ before error
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // reduce
|
||||
//this.reductionCount++;
|
||||
|
||||
len = this.productions_[action[1]][1];
|
||||
|
||||
// perform semantic action
|
||||
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
||||
// default location, uses first token for firsts, last for lasts
|
||||
yyval._$ = {
|
||||
first_line: lstack[lstack.length-(len||1)].first_line,
|
||||
last_line: lstack[lstack.length-1].last_line,
|
||||
first_column: lstack[lstack.length-(len||1)].first_column,
|
||||
last_column: lstack[lstack.length-1].last_column
|
||||
};
|
||||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
||||
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
}
|
||||
|
||||
// pop off stack
|
||||
if (len) {
|
||||
stack = stack.slice(0,-1*len*2);
|
||||
vstack = vstack.slice(0, -1*len);
|
||||
lstack = lstack.slice(0, -1*len);
|
||||
}
|
||||
|
||||
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
// goto new state = table[STATE][NONTERMINAL]
|
||||
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
|
||||
case 3: // accept
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}};
|
||||
/* Jison generated lexer */
|
||||
var lexer = (function(){
|
||||
var lexer = ({EOF:1,
|
||||
parseError:function parseError(str, hash) {
|
||||
if (this.yy.parseError) {
|
||||
this.yy.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
setInput:function (input) {
|
||||
this._input = input;
|
||||
this._more = this._less = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = '';
|
||||
this.conditionStack = ['INITIAL'];
|
||||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
||||
return this;
|
||||
},
|
||||
input:function () {
|
||||
var ch = this._input[0];
|
||||
this.yytext+=ch;
|
||||
this.yyleng++;
|
||||
this.match+=ch;
|
||||
this.matched+=ch;
|
||||
var lines = ch.match(/\n/);
|
||||
if (lines) this.yylineno++;
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
},
|
||||
unput:function (ch) {
|
||||
this._input = ch + this._input;
|
||||
return this;
|
||||
},
|
||||
more:function () {
|
||||
this._more = true;
|
||||
return this;
|
||||
},
|
||||
less:function (n) {
|
||||
this._input = this.match.slice(n) + this._input;
|
||||
},
|
||||
pastInput:function () {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||||
},
|
||||
upcomingInput:function () {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20-next.length);
|
||||
}
|
||||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
|
||||
},
|
||||
showPosition:function () {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c+"^";
|
||||
},
|
||||
next:function () {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) this.done = true;
|
||||
|
||||
var token,
|
||||
match,
|
||||
tempMatch,
|
||||
index,
|
||||
col,
|
||||
lines;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
this.match = '';
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i=0;i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (!this.options.flex) break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
lines = match[0].match(/\n.*/g);
|
||||
if (lines) this.yylineno += lines.length;
|
||||
this.yylloc = {first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno+1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.yyleng = this.yytext.length;
|
||||
this._more = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
|
||||
if (this.done && this._input) this.done = false;
|
||||
if (token) return token;
|
||||
else return;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
||||
{text: "", token: null, line: this.yylineno});
|
||||
}
|
||||
},
|
||||
lex:function lex() {
|
||||
var r = this.next();
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
},
|
||||
begin:function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
},
|
||||
popState:function popState() {
|
||||
return this.conditionStack.pop();
|
||||
},
|
||||
_currentRules:function _currentRules() {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
|
||||
},
|
||||
topState:function () {
|
||||
return this.conditionStack[this.conditionStack.length-2];
|
||||
},
|
||||
pushState:function begin(condition) {
|
||||
this.begin(condition);
|
||||
}});
|
||||
lexer.options = {};
|
||||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
|
||||
var YYSTATE=YY_START
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:/* skip whitespace */
|
||||
break;
|
||||
case 1:return 6
|
||||
break;
|
||||
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
|
||||
break;
|
||||
case 3:return 17
|
||||
break;
|
||||
case 4:return 18
|
||||
break;
|
||||
case 5:return 23
|
||||
break;
|
||||
case 6:return 24
|
||||
break;
|
||||
case 7:return 22
|
||||
break;
|
||||
case 8:return 21
|
||||
break;
|
||||
case 9:return 10
|
||||
break;
|
||||
case 10:return 11
|
||||
break;
|
||||
case 11:return 8
|
||||
break;
|
||||
case 12:return 14
|
||||
break;
|
||||
case 13:return 'INVALID'
|
||||
break;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/];
|
||||
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};
|
||||
|
||||
|
||||
;
|
||||
return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
return parser;
|
||||
})();
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.parser = jsonlint;
|
||||
exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }
|
||||
exports.main = function commonjsMain(args) {
|
||||
if (!args[1])
|
||||
throw new Error('Usage: '+args[0]+' FILE');
|
||||
if (typeof process !== 'undefined') {
|
||||
var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
|
||||
} else {
|
||||
var cwd = require("file").path(require("file").cwd());
|
||||
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
||||
}
|
||||
return exports.parser.parse(source);
|
||||
}
|
||||
if (typeof module !== 'undefined' && require.main === module) {
|
||||
exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32}
|
||||
diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a,
|
||||
b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a};
|
||||
diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,b,
|
||||
d):this.diff_bisect_(a,b,d)};
|
||||
diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b);a=d.chars1;b=d.chars2;d=d.lineArray;a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push([0,""]);for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case 1:e++;g+=a[b][1];break;case -1:d++;f+=a[b][1];break;case 0:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
|
||||
diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=f,h=2*f,j=Array(h),i=Array(h),k=0;k<h;k++)j[k]=-1,i[k]=-1;j[g+1]=0;i[g+1]=0;for(var k=d-e,q=0!=k%2,r=0,t=0,p=0,w=0,v=0;v<f&&!((new Date).getTime()>c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]<j[l+1]?j[l+1]:j[l-1]+1;for(var s=m-n;m<d&&s<e&&a.charAt(m)==b.charAt(s);)m++,s++;j[l]=m;if(m>d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l<h&&-1!=i[l])){var u=d-i[l];if(m>=
|
||||
u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]<i[l+1]?i[l+1]:i[l-1]+1;for(m=u-n;u<d&&m<e&&a.charAt(d-u-1)==b.charAt(e-m-1);)u++,m++;i[l]=u;if(u>d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l<h&&-1!=j[l])&&(m=j[l],s=g+m-l,u=d-u,m>=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]};
|
||||
diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)};
|
||||
diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;f<a.length-1;){f=a.indexOf("\n",c);-1==f&&(f=a.length-1);var r=a.substring(c,f+1),c=f+1;(e.hasOwnProperty?e.hasOwnProperty(r):void 0!==e[r])?b+=String.fromCharCode(e[r]):(b+=String.fromCharCode(g),e[r]=g,d[g++]=r)}return b}var d=[],e={};d[0]="";var f=c(a),g=c(b);return{chars1:f,chars2:g,lineArray:d}};
|
||||
diff_match_patch.prototype.diff_charsToLines_=function(a,b){for(var c=0;c<a.length;c++){for(var d=a[c][1],e=[],f=0;f<d.length;f++)e[f]=b[d.charCodeAt(f)];a[c][1]=e.join("")}};diff_match_patch.prototype.diff_commonPrefix=function(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(f,e)==b.substring(f,e)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
|
||||
diff_match_patch.prototype.diff_commonSuffix=function(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
|
||||
diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;for(var d=0,e=1;;){var f=a.substring(c-e),f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
|
||||
diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,j,n,l;-1!=(e=b.indexOf(d,e+1));){var m=f.diff_commonPrefix(a.substring(c),b.substring(e)),s=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<s+m&&(g=b.substring(e-s,e)+b.substring(e,e+m),h=a.substring(0,c-s),j=a.substring(c+m),n=b.substring(0,e-s),l=b.substring(e+m))}return 2*g.length>=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;
|
||||
var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4)),d=c(d,e,Math.ceil(d.length/2)),h;if(!g&&!d)return null;h=d?g?g[4].length>d[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]};
|
||||
diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f<a.length;)0==a[f][0]?(c[d++]=f,g=j,h=i,i=j=0,e=a[f][1]):(1==a[f][0]?j+=a[f][1].length:i+=a[f][1].length,e&&(e.length<=Math.max(g,h)&&e.length<=Math.max(j,i))&&(a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,d--,f=0<d?c[d-1]:-1,i=j=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<a.length;){if(-1==a[f-1][0]&&1==a[f][0]){b=a[f-1][1];c=a[f][1];
|
||||
d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}};
|
||||
diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);
|
||||
return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(0==a[c-1][0]&&0==a[c+1][0]){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g)var h=e.substring(e.length-g),d=d.substring(0,d.length-g),e=h+e.substring(0,e.length-g),f=h+f;for(var g=d,h=e,j=f,i=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){var d=d+e.charAt(0),e=e.substring(1)+f.charAt(0),f=f.substring(1),k=b(d,e)+b(e,f);k>=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=
|
||||
h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
|
||||
diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;f<a.length;){if(0==a[f][0])a[f][1].length<this.Diff_EditCost&&(j||i)?(c[d++]=f,g=j,h=i,e=a[f][1]):(d=0,e=null),j=i=!1;else if(-1==a[f][0]?i=!0:j=!0,e&&(g&&h&&j&&i||e.length<this.Diff_EditCost/2&&3==g+h+j+i))a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,e=null,g&&h?(j=i=!0,d=0):(d--,f=0<d?c[d-1]:-1,j=i=!1),b=!0;f++}b&&this.diff_cleanupMerge(a)};
|
||||
diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push([0,""]);for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case 1:d++;f+=a[b][1];b++;break;case -1:c++;e+=a[b][1];b++;break;case 0:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&0==a[b-c-d-1][0]?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,[0,f.substring(0,g)]),b++),f=f.substring(g),e=e.substring(g)),g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-
|
||||
g),e=e.substring(0,e.length-g))),0===c?a.splice(b-d,c+d,[1,f]):0===d?a.splice(b-c,c+d,[-1,e]):a.splice(b-c-d,c+d,[-1,e],[1,f]),b=b-c-d+(c?1:0)+(d?1:0)+1):0!==b&&0==a[b-1][0]?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)0==a[b-1][0]&&0==a[b+1][0]&&(a[b][1].substring(a[b][1].length-a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,
|
||||
a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){1!==a[g][0]&&(c+=a[g][1].length);-1!==a[g][0]&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)};
|
||||
diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],j=a[g][1],j=j.replace(c,"&").replace(d,"<").replace(e,">").replace(f,"¶<br>");switch(h){case 1:b[g]='<ins style="background:#e6ffe6;">'+j+"</ins>";break;case -1:b[g]='<del style="background:#ffe6e6;">'+j+"</del>";break;case 0:b[g]="<span>"+j+"</span>"}}return b.join("")};
|
||||
diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)-1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][0],g=a[e][1];switch(f){case 1:c+=g.length;break;case -1:d+=g.length;break;case 0:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
|
||||
diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case 1:b[c]="+"+encodeURI(a[c][1]);break;case -1:b[c]="-"+a[c][1].length;break;case 0:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
|
||||
diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=[1,decodeURI(h)]}catch(j){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var i=parseInt(h,10);if(isNaN(i)||0>i)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=i);"="==f[g].charAt(0)?c[d++]=[0,h]:c[d++]=[-1,h];break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+
|
||||
f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
|
||||
diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return!f.Match_Distance?g?1:e:e+g/f.Match_Distance}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<<b.length-1,h=-1,i,k,q=b.length+a.length,r,t=0;t<b.length;t++){i=0;for(k=q;i<k;)d(t,c+
|
||||
k)<=g?i=k:q=k,k=Math.floor((q-i)/2+i);q=k;i=Math.max(1,c-k+1);var p=Math.min(c+k,a.length)+b.length;k=Array(p+2);for(k[p+1]=(1<<t)-1;p>=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h};
|
||||
diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c<a.length;c++)b[a.charAt(c)]=0;for(c=0;c<a.length;c++)b[a.charAt(c)]|=1<<a.length-c-1;return b};
|
||||
diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift([0,c]);(d=b.substring(a.start2+a.length1,a.start2+a.length1+d))&&a.diffs.push([0,d]);a.start1-=c.length;a.start2-=c.length;a.length1+=
|
||||
c.length+d.length;a.length2+=c.length+d.length}};
|
||||
diff_match_patch.prototype.patch_make=function(a,b,c){var d;if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c)d=a,b=this.diff_main(d,b,!0),2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b));else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
|
||||
if(0===b.length)return[];c=[];a=new diff_match_patch.patch_obj;for(var e=0,f=0,g=0,h=d,j=0;j<b.length;j++){var i=b[j][0],k=b[j][1];!e&&0!==i&&(a.start1=f,a.start2=g);switch(i){case 1:a.diffs[e++]=b[j];a.length2+=k.length;d=d.substring(0,g)+k+d.substring(g);break;case -1:a.length1+=k.length;a.diffs[e++]=b[j];d=d.substring(0,g)+d.substring(g+k.length);break;case 0:k.length<=2*this.Patch_Margin&&e&&b.length!=j+1?(a.diffs[e++]=b[j],a.length1+=k.length,a.length2+=k.length):k.length>=2*this.Patch_Margin&&
|
||||
e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=d.diffs[f].slice();e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
|
||||
diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];a=this.patch_deepCopy(a);var c=this.patch_addPadding(a);b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),j,i=-1;if(h.length>this.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);
|
||||
if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;i<a[f].diffs.length;i++){var q=a[f].diffs[i];0!==q[0]&&(k=this.diff_xIndex(g,h));1===q[0]?b=b.substring(0,
|
||||
j+k)+q[1]+b.substring(j+k):-1===q[0]&&(b=b.substring(0,j+k)+b.substring(j+this.diff_xIndex(g,h+q[1].length)));-1!==q[0]&&(h+=q[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
|
||||
diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;var d=a[0],e=d.diffs;if(0==e.length||0!=e[0][0])e.unshift([0,c]),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,
|
||||
c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
|
||||
diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,j=!0;h.start1=e-g.length;h.start2=f-g.length;""!==g&&(h.length1=h.length2=g.length,h.diffs.push([0,g]));for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){var g=d.diffs[0][0],i=d.diffs[0][1];1===g?(h.length2+=i.length,f+=i.length,h.diffs.push(d.diffs.shift()),
|
||||
j=!1):-1===g&&1==h.diffs.length&&0==h.diffs[0][0]&&i.length>2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&
|
||||
(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
|
||||
diff_match_patch.prototype.patch_fromText=function(a){var b=[];if(!a)return b;a=a.split("\n");for(var c=0,d=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;c<a.length;){var e=a[c].match(d);if(!e)throw Error("Invalid patch string: "+a[c]);var f=new diff_match_patch.patch_obj;b.push(f);f.start1=parseInt(e[1],10);""===e[2]?(f.start1--,f.length1=1):"0"==e[2]?f.length1=0:(f.start1--,f.length1=parseInt(e[2],10));f.start2=parseInt(e[3],10);""===e[4]?(f.start2--,f.length2=1):"0"==e[4]?f.length2=0:(f.start2--,f.length2=
|
||||
parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push([-1,g]);else if("+"==e)f.diffs.push([1,g]);else if(" "==e)f.diffs.push([0,g]);else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
|
||||
diff_match_patch.patch_obj.prototype.toString=function(){var a,b;a=0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1;b=0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2;a=["@@ -"+a+" +"+b+" @@\n"];var c;for(b=0;b<this.diffs.length;b++){switch(this.diffs[b][0]){case 1:c="+";break;case -1:c="-";break;case 0:c=" "}a[b+1]=c+encodeURI(this.diffs[b][1])+"\n"}return a.join("").replace(/%20/g," ")};
|
||||
this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=-1;this.DIFF_INSERT=1;this.DIFF_EQUAL=0;})()
|
||||
@@ -0,0 +1,831 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
|
||||
"await": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "type"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("class"),
|
||||
"implements": C,
|
||||
"namespace": C,
|
||||
"module": kw("module"),
|
||||
"enum": kw("module"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("modifier"),
|
||||
"private": kw("modifier"),
|
||||
"protected": kw("modifier"),
|
||||
"abstract": kw("modifier"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "boolean": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/o/i)) {
|
||||
stream.eatWhile(/[0-7]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/b/i)) {
|
||||
stream.eatWhile(/[01]/i);
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
if (ch != ">" || !state.lexical || state.lexical.type != ">")
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current()
|
||||
if (state.lastType != ".") {
|
||||
if (keywords.propertyIsEnumerable(word)) {
|
||||
var kw = keywords[word]
|
||||
return ret(kw.type, kw.style, word)
|
||||
}
|
||||
if (word == "async" && stream.match(/^\s*[\(\w]/, false))
|
||||
return ret("async", "keyword", word)
|
||||
}
|
||||
return ret("variable", "variable", word)
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
if (isTS) { // Try to skip TypeScript return type declarations after the arguments
|
||||
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
|
||||
if (m) arrow = m.index
|
||||
}
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (/["'\/]/.test(ch)) {
|
||||
return;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") {
|
||||
if (isTS && value == "type") {
|
||||
cx.marked = "keyword"
|
||||
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
|
||||
} else {
|
||||
return cont(pushlex("stat"), maybelabel);
|
||||
}
|
||||
}
|
||||
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
|
||||
if (type == "async") return cont(statement)
|
||||
if (value == "@") return cont(expression, statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function parenExpr(type) {
|
||||
if (type != "(") return pass()
|
||||
return cont(pushlex(")"), expression, expect(")"), poplex)
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
|
||||
if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "async") {
|
||||
cx.marked = "property";
|
||||
return cont(objprop);
|
||||
} else if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "modifier") {
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression, afterprop);
|
||||
} else if (type == ":") {
|
||||
return pass(afterprop)
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end, sep) {
|
||||
function proceed(type, value) {
|
||||
if (sep ? sep.indexOf(type) > -1 : type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(function(type, value) {
|
||||
if (type == end || value == end) return pass()
|
||||
return pass(what)
|
||||
}, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
if (type == end || value == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type, value) {
|
||||
if (isTS) {
|
||||
if (type == ":") return cont(typeexpr);
|
||||
if (value == "?") return cont(maybetype);
|
||||
}
|
||||
}
|
||||
function typeexpr(type) {
|
||||
if (type == "variable") {cx.marked = "type"; return cont(afterType);}
|
||||
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
|
||||
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
|
||||
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
|
||||
}
|
||||
function maybeReturnType(type) {
|
||||
if (type == "=>") return cont(typeexpr)
|
||||
}
|
||||
function typeprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property"
|
||||
return cont(typeprop)
|
||||
} else if (value == "?") {
|
||||
return cont(typeprop)
|
||||
} else if (type == ":") {
|
||||
return cont(typeexpr)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, maybetype, expect("]"), typeprop)
|
||||
}
|
||||
}
|
||||
function typearg(type) {
|
||||
if (type == "variable") return cont(typearg)
|
||||
else if (type == ":") return cont(typeexpr)
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
if (value == "|" || type == ".") return cont(typeexpr)
|
||||
if (type == "[") return cont(expect("]"), afterType)
|
||||
if (value == "extends") return cont(typeexpr)
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "modifier") return cont(pattern)
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype, maybeAssign);
|
||||
}
|
||||
function classExpression(type, value) {
|
||||
// Class expressions may have an optional name.
|
||||
if (type == "variable") return className(type, value);
|
||||
return classNameAfter(type, value);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
|
||||
if (value == "extends" || value == "implements" || (isTS && type == ","))
|
||||
return cont(isTS ? typeexpr : expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
if ((value == "async" || value == "static" || value == "get" || value == "set" ||
|
||||
(isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
|
||||
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
cx.marked = "property";
|
||||
return cont(isTS ? classfield : functiondef, classBody);
|
||||
}
|
||||
if (type == "[")
|
||||
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
if (value == "@") return cont(expression, classBody)
|
||||
}
|
||||
function classfield(type, value) {
|
||||
if (value == "?") return cont(classfield)
|
||||
if (type == ":") return cont(typeexpr, maybeAssign)
|
||||
if (value == "=") return cont(expressionNoComma)
|
||||
return pass(functiondef)
|
||||
}
|
||||
function afterExport(type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
|
||||
return pass(statement);
|
||||
}
|
||||
function exportField(type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
|
||||
if (type == "variable") return pass(expressionNoComma, exportField);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeMoreImports, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeMoreImports(type) {
|
||||
if (type == ",") return cont(importSpec, maybeMoreImports)
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
while ((lexical.type == "stat" || lexical.type == "form") &&
|
||||
(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
|
||||
(top == maybeoperatorComma || top == maybeoperatorNoComma) &&
|
||||
!/^[,\.=+\-*:?[\(]/.test(textAfter))))
|
||||
lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
skipExpression: function(state) {
|
||||
var top = state.cc[state.cc.length - 1]
|
||||
if (top == expression || top == expressionNoComma) state.cc.pop()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
||||
2
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/js/jquery.js
vendored
Normal file
2
xtoon-ops/xtoon-register-server/src/main/resources/static/console-ui/public/js/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/bat",["require","exports"],function(e,s){"use strict";Object.defineProperty(s,"__esModule",{value:!0}),s.conf={comments:{lineComment:"REM"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}]},s.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".bat",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"}],keywords:/call|defined|echo|errorlevel|exist|for|goto|if|pause|set|shift|start|title|not|pushd|popd/,symbols:/[=><!~?&|+\-*\/\^;\.,]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^(\s*)(rem(?:\s.*|))$/,["","comment"]],[/(\@?)(@keywords)(?!\w)/,[{token:"keyword"},{token:"keyword.$2"}]],[/[ \t\r\n]+/,""],[/setlocal(?!\w)/,"keyword.tag-setlocal"],[/endlocal(?!\w)/,"keyword.tag-setlocal"],[/[a-zA-Z_]\w*/,""],[/:\w*/,"metatag"],[/%[^%]+%/,"variable"],[/%%[\w]+(?!\w)/,"variable"],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F_]*[0-9a-fA-F]/,"number.hex"],[/\d+/,"number"],[/[;,.]/,"delimiter"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],string:[[/[^\\"'%]+/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/%[\w ]+%/,"variable"],[/%%[\w]+(?!\w)/,"variable"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/$/,"string","@popall"]]}}});
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/coffee",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\$\-\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{blockComment:["###","###"],lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".coffee",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],regEx:/\/(?!\/\/)(?:[^\/\\]|\\.)*\/[igm]*/,keywords:["and","or","is","isnt","not","on","yes","@","no","off","true","false","null","this","new","delete","typeof","in","instanceof","return","throw","break","continue","debugger","if","else","switch","for","while","do","try","catch","finally","class","extends","super","undefined","then","unless","until","loop","of","by","when"],symbols:/[=><!~?&%|+\-*\/\^\.,\:]+/,escapes:/\\(?:[abfnrtv\\"'$]|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/\@[a-zA-Z_]\w*/,"variable.predefined"],[/[a-zA-Z_]\w*/,{cases:{this:"variable.predefined","@keywords":{token:"keyword.$0"},"@default":""}}],[/[ \t\r\n]+/,""],[/###/,"comment","@comment"],[/#.*$/,"comment"],["///",{token:"regexp",next:"@hereregexp"}],[/^(\s*)(@regEx)/,["","regexp"]],[/(\()(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\,)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\=)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\:)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\[)(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\!)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\&)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\|)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\?)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\{)(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\;)(\s*)(@regEx)/,["","","regexp"]],[/}/,{cases:{"$S2==interpolatedstring":{token:"string",next:"@pop"},"@default":"@brackets"}}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d+[eE]([\-+]?\d+)?/,"number.float"],[/\d+\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F]+/,"number.hex"],[/0[0-7]+(?!\d)/,"number.octal"],[/\d+/,"number"],[/[,.]/,"delimiter"],[/"""/,"string",'@herestring."""'],[/'''/,"string","@herestring.'''"],[/"/,{cases:{"@eos":"string","@default":{token:"string",next:'@string."'}}}],[/'/,{cases:{"@eos":"string","@default":{token:"string",next:"@string.'"}}}]],string:[[/[^"'\#\\]+/,"string"],[/@escapes/,"string.escape"],[/\./,"string.escape.invalid"],[/\./,"string.escape.invalid"],[/#{/,{cases:{'$S2=="':{token:"string",next:"root.interpolatedstring"},"@default":"string"}}],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/#/,"string"]],herestring:[[/("""|''')/,{cases:{"$1==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/[^#\\'"]+/,"string"],[/['"]+/,"string"],[/@escapes/,"string.escape"],[/\./,"string.escape.invalid"],[/#{/,{token:"string.quote",next:"root.interpolatedstring"}],[/#/,"string"]],comment:[[/[^#]+/,"comment"],[/###/,"comment","@pop"],[/#/,"comment"]],hereregexp:[[/[^\\\/#]+/,"regexp"],[/\\./,"regexp"],[/#.*$/,"comment"],["///[igm]*",{token:"regexp",next:"@pop"}],[/\//,"regexp"]]}}});
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/cpp",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"[",close:"]"},{open:"{",close:"}"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={defaultToken:"",tokenPostfix:".cpp",brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"},{token:"delimiter.angle",open:"<",close:">"}],keywords:["abstract","amp","array","auto","bool","break","case","catch","char","class","const","constexpr","const_cast","continue","cpu","decltype","default","delegate","delete","do","double","dynamic_cast","each","else","enum","event","explicit","export","extern","false","final","finally","float","for","friend","gcnew","generic","goto","if","in","initonly","inline","int","interface","interior_ptr","internal","literal","long","mutable","namespace","new","noexcept","nullptr","__nullptr","operator","override","partial","pascal","pin_ptr","private","property","protected","public","ref","register","reinterpret_cast","restrict","return","safe_cast","sealed","short","signed","sizeof","static","static_assert","static_cast","struct","switch","template","this","thread_local","throw","tile_static","true","try","typedef","typeid","typename","union","unsigned","using","virtual","void","volatile","wchar_t","where","while","_asm","_based","_cdecl","_declspec","_fastcall","_if_exists","_if_not_exists","_inline","_multiple_inheritance","_pascal","_single_inheritance","_stdcall","_virtual_inheritance","_w64","__abstract","__alignof","__asm","__assume","__based","__box","__builtin_alignof","__cdecl","__clrcall","__declspec","__delegate","__event","__except","__fastcall","__finally","__forceinline","__gc","__hook","__identifier","__if_exists","__if_not_exists","__inline","__int128","__int16","__int32","__int64","__int8","__interface","__leave","__m128","__m128d","__m128i","__m256","__m256d","__m256i","__m64","__multiple_inheritance","__newslot","__nogc","__noop","__nounwind","__novtordisp","__pascal","__pin","__pragma","__property","__ptr32","__ptr64","__raise","__restrict","__resume","__sealed","__single_inheritance","__stdcall","__super","__thiscall","__try","__try_cast","__typeof","__unaligned","__unhook","__uuidof","__value","__virtual_inheritance","__w64","__wchar_t"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,integersuffix:/(ll|LL|u|U|l|L)?(ll|LL|u|U|l|L)?/,floatsuffix:/[fFlL]?/,tokenizer:{root:[[/[a-zA-Z_]\w*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/\[\[.*\]\]/,"annotation"],[/^\s*#\w+/,"keyword"],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/,"number.float"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F](@integersuffix)/,"number.hex"],[/0[0-7']*[0-7](@integersuffix)/,"number.octal"],[/0[bB][0-1']*[0-1](@integersuffix)/,"number.binary"],[/\d[\d']*\d(@integersuffix)/,"number"],[/\d(@integersuffix)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@doccomment"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],doccomment:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]]}}});
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/csharp",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}]},t.language={defaultToken:"",tokenPostfix:".cs",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],keywords:["extern","alias","using","bool","decimal","sbyte","byte","short","ushort","int","uint","long","ulong","char","float","double","object","dynamic","string","assembly","is","as","ref","out","this","base","new","typeof","void","checked","unchecked","default","delegate","var","const","if","else","switch","case","while","do","for","foreach","in","break","continue","goto","return","throw","try","catch","finally","lock","yield","from","let","where","join","on","equals","into","orderby","ascending","descending","select","group","by","namespace","partial","class","field","event","method","param","property","public","protected","internal","private","abstract","sealed","static","struct","readonly","volatile","virtual","override","params","get","set","add","remove","operator","true","false","implicit","explicit","interface","enum","null","async","await","fixed","sizeof","stackalloc","unsafe","nameof","when"],namespaceFollows:["namespace","using"],parenFollows:["if","for","while","switch","foreach","using","catch","when"],operators:["=","??","||","&&","|","^","&","==","!=","<=",">=","<<","+","-","*","/","%","!","~","++","--","+=","-=","*=","/=","%=","&=","|=","^=","<<=",">>=",">>","=>"],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/\@?[a-zA-Z_]\w*/,{cases:{"@namespaceFollows":{token:"keyword.$0",next:"@namespace"},"@keywords":{token:"keyword.$0",next:"@qualified"},"@default":{token:"identifier",next:"@qualified"}}}],{include:"@whitespace"},[/}/,{cases:{"$S2==interpolatedstring":{token:"string.quote",next:"@pop"},"$S2==litinterpstring":{token:"string.quote",next:"@pop"},"@default":"@brackets"}}],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/[0-9_]*\.[0-9_]+([eE][\-+]?\d+)?[fFdD]?/,"number.float"],[/0[xX][0-9a-fA-F_]+/,"number.hex"],[/0[bB][01_]+/,"number.hex"],[/[0-9_]+/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,{token:"string.quote",next:"@string"}],[/\$\@"/,{token:"string.quote",next:"@litinterpstring"}],[/\@"/,{token:"string.quote",next:"@litstring"}],[/\$"/,{token:"string.quote",next:"@interpolatedstring"}],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],qualified:[[/[a-zA-Z_][\w]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],[/\./,"delimiter"],["","","@pop"]],namespace:[{include:"@whitespace"},[/[A-Z]\w*/,"namespace"],[/[\.=]/,"delimiter"],["","","@pop"]],comment:[[/[^\/*]+/,"comment"],["\\*/","comment","@pop"],[/[\/*]/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",next:"@pop"}]],litstring:[[/[^"]+/,"string"],[/""/,"string.escape"],[/"/,{token:"string.quote",next:"@pop"}]],litinterpstring:[[/[^"{]+/,"string"],[/""/,"string.escape"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.litinterpstring"}],[/"/,{token:"string.quote",next:"@pop"}]],interpolatedstring:[[/[^\\"{]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.interpolatedstring"}],[/"/,{token:"string.quote",next:"@pop"}]],whitespace:[[/^[ \t\v\f]*#((r)|(load))(?=\s)/,"directive.csx"],[/^[ \t\v\f]*#\w.*$/,"namespace.cpp"],[/[ \t\v\f\r\n]+/,""],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]]}}});
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/css",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g,comments:{blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={defaultToken:"",tokenPostfix:".css",ws:"[ \t\n\r\f]*",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.bracket"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@selector"}],selector:[{include:"@comments"},{include:"@import"},{include:"@strings"},["[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)",{token:"keyword",next:"@keyframedeclaration"}],["[@](page|content|font-face|-moz-document)",{token:"keyword"}],["[@](charset|namespace)",{token:"keyword",next:"@declarationbody"}],["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@selectorname"},["[\\*]","tag"],["[>\\+,]","delimiter"],["\\[",{token:"delimiter.bracket",next:"@selectorattribute"}],["{",{token:"delimiter.bracket",next:"@selectorbody"}]],selectorbody:[{include:"@comments"},["[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))","attribute.name","@rulevalue"],["}",{token:"delimiter.bracket",next:"@pop"}]],selectorname:[["(\\.|#(?=[^{])|%|(@identifier)|:)+","tag"]],selectorattribute:[{include:"@term"},["]",{token:"delimiter.bracket",next:"@pop"}]],term:[{include:"@comments"},["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@functioninvocation"},{include:"@numbers"},{include:"@name"},["([<>=\\+\\-\\*\\/\\^\\|\\~,])","delimiter"],[",","delimiter"]],rulevalue:[{include:"@comments"},{include:"@strings"},{include:"@term"},["!important","keyword"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],warndebug:[["[@](warn|debug)",{token:"keyword",next:"@declarationbody"}]],import:[["[@](import)",{token:"keyword",next:"@declarationbody"}]],urldeclaration:[{include:"@strings"},["[^)\r\n]+","string"],["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],parenthizedterm:[{include:"@term"},["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],declarationbody:[{include:"@term"},[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[/[^*/]+/,"comment"],[/./,"comment"]],name:[["@identifier","attribute.value"]],numbers:[["-?(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],keyframedeclaration:[["@identifier","attribute.value"],["{",{token:"delimiter.bracket",switchTo:"@keyframebody"}]],keyframebody:[{include:"@term"},["{",{token:"delimiter.bracket",next:"@selectorbody"}],["}",{token:"delimiter.bracket",next:"@pop"}]],functioninvocation:[["@identifier\\(",{token:"attribute.value",next:"@functionarguments"}]],functionarguments:[["\\$@identifier@ws:","attribute.name"],["[,]","delimiter"],{include:"@term"},["\\)",{token:"attribute.value",next:"@pop"}]],strings:[['~?"',{token:"string",next:"@stringenddoublequote"}],["~?'",{token:"string",next:"@stringendquote"}]],stringenddoublequote:[["\\\\.","string"],['"',{token:"string",next:"@pop"}],[/[^\\"]+/,"string"],[".","string"]],stringendquote:[["\\\\.","string"],["'",{token:"string",next:"@pop"}],[/[^\\']+/,"string"],[".","string"]]}}});
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!-----------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
|
||||
* Released under the MIT license
|
||||
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
|
||||
*-----------------------------------------------------------------------------*/
|
||||
define("vs/basic-languages/src/dockerfile",["require","exports"],function(e,s){"use strict";Object.defineProperty(s,"__esModule",{value:!0}),s.conf={brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},s.language={defaultToken:"",tokenPostfix:".dockerfile",instructions:/FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|LABEL|USER|WORKDIR|COPY|CMD|STOPSIGNAL|SHELL|ENTRYPOINT/,instructionAfter:/ONBUILD/,variableAfter:/ENV/,variable:/\${?[\w]+}?/,tokenizer:{root:[{include:"@whitespace"},{include:"@comment"},[/(@instructionAfter)(\s+)/,["keyword",{token:"",next:"@instructions"}]],["","keyword","@instructions"]],instructions:[[/(@variableAfter)(\s+)([\w]+)/,["keyword","",{token:"variable",next:"@arguments"}]],[/(@instructions)/,"keyword","@arguments"]],arguments:[{include:"@whitespace"},{include:"@strings"},[/(@variable)/,{cases:{"@eos":{token:"variable",next:"@popall"},"@default":"variable"}}],[/\\/,{cases:{"@eos":"","@default":""}}],[/./,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],whitespace:[[/\s+/,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],comment:[[/(^#.*$)/,"comment","@popall"]],strings:[[/'$/,"string","@popall"],[/'/,"string","@stringBody"],[/"$/,"string","@popall"],[/"/,"string","@dblStringBody"]],stringBody:[[/[^\\\$']/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/'$/,"string","@popall"],[/'/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]],dblStringBody:[[/[^\\\$"]/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/"$/,"string","@popall"],[/"/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]]}}});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user